Mark Wilden pointed me to a post he's written about his experience pair programming at Pivotal Labs where he makes some interesting although not uncommon observations.
When you pair program, you're effectively joined at the hip with your pair. You can't pair if only one of you is there.
I've previously written wondering what we should do if our pair isn't around where I was leaning more towards the opinion that we should try to continue along the same path that we were on when working with our pair if they're gone for a short amount of time and to find a new pair or work alone if they're gone for longer.
On the projects I've worked on we'll still have times working alone when there's an odd number of people around or if someone just feels like working on their own and I think that's fine as well. I don't think we need to pair 100% of the time.
You have to be able to think out loud – 8 hours a day. Then you have to type in code while someone is watching you. They'll catch your typos (hopefully after giving you a chance to spot them yourself) and they'll see when you're floundering for how to do something.
I find that this is quite a useful practice for explaining things to yourself although I can see how it would initially exhausting.
Even now there are times when I just want to write some code instead of having to explain what I want to do to someone else. Sadly almost every time I explain something it turns out that my pair has a better idea of how to do it than me so I'm always glad pairing encourages this conversation.
Pair programming doesn't encourage quiet reflection and exploration. You can't just sit back and read some code. You can't just sit and think. I mean, you can, but then your pair is just sitting there.
This is a bit of a double edged sword – pair programming does encourage us to get things done but it's also true that sometimes we need to get the whiteboard out.
Often just sketching out the problem on a piece of paper to check your understanding is enough to trigger a conversation which might result in a better solution.
It does tend to need one person to drive this process though. I haven't seen it just happen organically.
We rarely pair 100% of the time so there are often times when you get a bit of time to play around a bit with the code and see whether specific approaches would work out and I often use this time for reflection and exploration.
One thing which a couple of the commenters on the original blog suggested is that perhaps more rotation was needed to help overcome some of the problems and from my experience it's vital that we do rotate otherwise the pair will end up hating each other!
I recently worked on a story with 3 other people across its life and each person pointed out something that I hadn't previously considered and which led to an eventual output that was much better than it would have been otherwise.
I think rotating different people onto a story can help lead to more innovative design as long as we have people working together who are relatively flexible and open to trying out new ideas.
Mark's post is certainly interesting though and helps identify some of the things we need to be aware of when pair programming – we don't just want to follow the practice blindly.
In order to execute Ruby code as fast as possible, Rubinius has the ability to compile Ruby code all the way down to machine code when it detects that a method is heavily used. In Rubinius, the system that manages this process is its JIT.
In today’s post, I’ll be giving an overview of the various players involved in the path that code takes to get from source to machine code. Without further ado, I’ll jump right in.
Melbourne ParserThis is the first step. The parser takes Ruby source code as input and calls for each element to create an internal representation of the code: the AST. (lib/ext/melbourne)
CompilerThe compiler takes the AST that the parser created and analyzes it, creating bytecode in the form of a CompiledMethod and InstructionSequence. (lib/compiler)
BytecodeA CompiledMethod object contains an InstructionSequence object, which is the raw bytecode which will perform the semantic actions of the Ruby source code. (lib/compiler/iseq.rb)
Virtual MachineThe VM itself then executes the bytecode using a simple interpreter. A key data structure used in this evaluation is the VMMethod, which is an internal mirror of a CompiledMethod, but translated into constructs that are easier to interpret. As the VM interprets a VMMethod, it uses InlineCache objects to speed up method dispatch. In addition, these InlineCache objects remember profiling information about what methods they have seen. This information is later used by the JIT.
The VM also increments a call counter on the VMMethod at a few critical points (on start and on backward branch). This call counter is what controls when the JIT kicks in. When the call counter reaches some predetermined value (controlled via -Xjit.call_til_compile), the first stage of the JIT kicks in.
Method ChooserNow that a call counter has reached the proper level, the JIT is ready to kick in. The JIT could simply take the method whose counter has hit the level, but instead it starts the search. It’s looking for a good method to JIT, which it finds by looking up the call stack.
The reason it does this is because the JIT has the ability to inline methods into methods that call them. We’re exploiting the fact that the call stack shows not just one method heating up, but a whole chain of them (vm/llvm/jit:compile_callframe). So we walk up the call stack, looking at each method along the way, and asking ourselves: could this method be inlined into the one that called it? If the answer is yes, we move to the next method. By doing this, we’re able to inline methods along hot paths in code, which yields better speeds.
Compiler ThreadNow that we’ve picked a good method at which to start the JIT process, the method is placed into a queue. This queue is then automatically emptied by another native thread, which is always running. It’s in this background thread that the rest of the JIT process takes place.
Using a background thread means that the Ruby code is free to continue to run while the JIT runs in the background. This means that the JIT imposes virtually no slowdown, because it never stands in the way of running Ruby code (vm/llvm/jit:compile_soon).
The JIT thread pops an entry off the queue and begins compiling it. Because the JIT uses LLVM to perform low level optimizations and machine code generation, we need to translate the method into a structure that LLVM understands. This structure is the LLVM IR.
To convert the method, we walk through the bytecode and call methods on a JITVisit object (one for each kind of bytecode). The JITVisit class uses LLVM’s IRBuilder class to build a big tree data structure that represents the actions that should be taken.
A simple example is that a goto bytecode instruction is translated into a Branch object and inserted into the IR. For most bytecode, the process is fairly straight forward, there being a simple set of IR objects to generate per bytecode.
Method InliningThe most complicated bytecodes to generate IR for are the send instructions. This is because it’s at these points that we have the opportunity to inline a method. When a method is inlined, the code to perform the method is inserted where the send instruction would normally be. This eliminates any calling overhead and allows LLVM to optimize more.
At this stage, control is handled to an Inliner object. The Inliner will only inline a method if it can see that the method was the the primary method called at a particular send instruction. Because Ruby is a dynamic language, any method call can always invoke a brand new method. But in reality, that happens rarely. Instead, most method calls always end up calling the same method over and over again. The profiling information that the InlineCaches have been gathering allows us to see that this is the case and perform inlining.
One constraint that the Inliner has is that it needs to avoid over-inlining. Over-inlining causes the generated function to become extremely large and slower than it would be if there were no inlining. To do this, the Inliner keeps track of the cost of a inlining. For every method that is inlined, the cost increases. When the cost reaches a threshold, no more inlining takes place.
Now that the Inliner has decided to go ahead and inline the method, it must insert a guard before the inlined code. This guard makes sure that the object is still of the type seen in the profiling information, and that therefore the inlined method code is the proper code to run. The generated IR for this looks something like:
if(obj->class == profiled_class) {
result = inlined_code_for_method_name;
} else {
result = obj->send method_name, …;
}
This allows Ruby code to continue to be dynamic, but exploits those points in the code where the dispatch is actually static.
After the JITVisit class has finished, control is handed off to optimize and generates machine code.
LLVM OptimizationUp to now, we’ve simply been constructing information to feed to LLVM. Now we actually hand over the IR to LLVM. The first thing LLVM does is run a number of optimization passes over the IR. This cleans up the IR and makes it quite a bit more efficient. At this stage, the IR can be reduced in size by five to ten times by remove redundancies and reordering.
LLVM Code GenerationFinally, the optimized IR is run through LLVMs code generator. This code generator is fairly complex, but its API is extremely simple. When the generator finishes, it returns a function pointer that can be called to execute the code. We put this function pointer into a special slot on the original CompiledMethod.
By default, this slot in the object holds a pointer to the function that implements the interpreter. By swapping them, any future calling of the method automatically uses the new JIT’d version.
DeoptimizationBecause Ruby is so dynamic, there are cases where JIT’d code must be discarded. The primary example is where a method that was inlined is redefined. In this case, the VM keeps a table to know all methods that inlined the method being redefined. It resets those methods back to using the interpreter and tags the JIT’d code to be discarded. Because the method has been reset, it can now be JIT’d again later, incorporating the newly redefined method.
So those are the systems that interaction to make speed up Ruby. The process can achieve speeds up by as much as 10x over non JIT’d code. We’ve only begun to scratch the surface of the techniques we can use to strip even more dynamic aspects of the code away and make it faster. 2010 is going to be an exciting year.
Steve Berczuk has a lovely discussion of Manage Your Project Portfolio. You can see his review here.
Geoff Crane of Paper Cut Project Monitoring described his TwitterView with Jhaymee Wilson. I had not heard of a "TwitterView" before this. It seems to be an interview over Twitter.
I've been interviewed twice this year (2010), once by PMI for an upcoming article and other time for a commercial Blog. Both times were around an hour on the phone and an editorial session after to do the "fact check" and final edits of the interviews.
What came to mind with Geoff's post is doing an interview with two tuna fish cans and a string.
We did this as kids. It's half duplex, low fidelity, highly distorted. Fun but not very effective.
Endless studies have shown that communication between people is largely through body language and expressions. Then comes tonality, and finally the words themselves.
Now I enjoy Geoff's Blog very much and the people he points us too as well.
But I still have gotten my mind around the notion of Twitter as a communication channel for anything other than exchanging short - almost context free - messages.
I live on IM with our field staff. It's a way to see who's in, a quick check up on something that can be resolved in a very few sentences - like ONE. For example - "who's using the WebEx account?" "Hey Matt, I'm headed to 59th facility, you gonna be there for lunch?" "Hannah, you coming to Breck this weekend with your roommates?" "Honey, stop by Safeway and get two bunches of green onions." Stuff like that.
Serious adult communication seems to require a wide channel.
Managing projects requires an even wide channel. No waving, no doodling on the reports, no looking at multiple pieces of paper at the same time, no sensing of the facial expressions to see if we're actually exchanging information rather than just textual characters.
Someone please tell me what am I missing here, where the PM2.0 advocates claim this is the "next big thing," in the domain of Project Management?
It is perhaps a myth, but an enduring one, that people and their pets resemble one another. The same has been said of products and the teams that build them. If it is true that a product reflects the structure of the team that built it, then an important decision for any Scrum project is how to organize individuals into teams. This paper presents a set of guidelines to consider in designing an appropriate team structure. Each guideline is presented in the form of a question to be asked of a current or proposed team. The questions are intended to be asked iteratively. Ask each question of a current or proposed team, changing the structure as appropriate based on the answer. As the structure changes, re-ask the questions until you can answer “yes” to each.
An effective team structure is one of the most critical factors in the success of any agile endeavor. Poorly structured teams will lead to inefficient teamwork, excessive integration challenges, multitasking, low morale and other problems. By using these nine questions to carefully consider how teams are organized you can avoid these problems.
Interested in helping a cutting-edge, high-growth startup scale? Squarespace, which was profiled here last year in Squarespace Architecture - A Grid Handles Hundreds of Millions of Requests a Month and also hosts this blog, is currently in the market for a crack scalability engineer to help build out its cloud infrastructure. Squarespace is very excited about finding a full-time scaling expert.
Interested applicants should go to http://www.squarespace.com/jobs-software-engineer for more information.
If you would like to advertise your critical, hard to fill job opeinings on HighScalability, please contact us and we'll get it setup for you.
This is an excerpt from my article Building Super Scalable Systems: Blade Runner Meets Autonomic Computing in the Ambient Cloud.
As I was writing an article on the architecture of the Storm Botnet, I couldn't help but notice the deep similarity of how Storm works and changes we're seeing in the evolution of political systems. In particular, the rise of the virtual-state. As crazy as this may sound, I think this is also the direction applications will need follow to survive in a complex world of billions of compute devices.
You may have already heard of virtual corporations. Virtual corporations are companies with limited office space, a distributed workforce, and production facilities located wherever it is profitable to locate them. The idea is to stay lean and compete using the rapid development and introduction of new products into high value-added markets. If you spot a market opportunity with a small time window, building your own factories and hiring and engineering team simply isn't an option. Building factories is a bit old fashioned and is left to the select few. These days you get an idea for a product and contract out everything else you possibly can. It doesn't really matter where you are located or where any of your partners are located. If part of your product requires a specialized microprocessor, for example, you'll contract out the R&D and the design. The manufacture will be contracted out to a virtual fab, then the chip will be sent to a contract manufacturing service for integration. Look ma, no hands.
Futurists say land doesn't matter anymore. Nations don't matter anymore. Entire relationships are abstractly represented by flows of money, contracts, information, and products between all these different agents. Interestingly enough, what technology is the absolute master of managing flows? Applications! But we are getting ahead of ourselves here.
Note: This essay was originally blogged in June 2009. It has been re-edited and so here it is . . .
Involvement Versus Focus; That Is The Question
Thomas M. Cagley Jr
The American Heritage Dictionary defines involvement as “the act of sharing in the activities of a group”. At its core, I would suggest the concept boils down to collaboration between involved parties to achieve a common goal. I think we can all agree upon the ideal of using collaborative groups to conquer many types of projects. Workers acting in a concerted manner in real life leads to pressure on several organizational fronts in order to achieve this ideal. In a future essay we will explore another of my simple checklists (see www.tcagley.wordpress.com) to implementing involvement but in this essay I would like to discuss the impact of a common goal. In many organizations the management structure in use is the command and control methodology. In this method decisions are made at the top of the management pyramid then get transmitted to line management and then to project teams at the epicenter of work. In this model, management knows best because of experience, advanced degrees, having gone to a seminar or just divine right. To those being affected it doesn’t matter.
Most process improvement programs extol the virtue of focusing on the needs of the organization or a specific class of users (usually senior or middle management). All said and done the virtue of focus is important but it is no longer sufficient to make change actually happen. The “organization” is being taken over by the World of Warcraft generation. This new crowd is beginning to believe they need to be involved if they are going to be asked to change how they are going to work. An example of that new expectation of involvement is reflected in the agile movement. Teams control how they do work and to an extent the work they will accept into the sprint. To the new generation, focus without involvement has come to mean big brother. Telling this new generation what to do whether you have their best interest in mind is deemed a paternalistic action, and for those with an expectation of being involved in their future, paternalism is at best grating and perhaps degrading. What does involvement mean? What is the new requirement to help an organization mature in terms of discipline and capability?
The collaborative model suggests a different model in which management sets forth the goal then engages all parties to chart the course forward. Would the classic waterfall implementation of the CMMI survive a collaborative approach or would a more interesting approach to the discipline of software engineering emerge? I suggest that in combination the structure of the CMMI and the collaborative nature of AGILE methods are the natural outcome in today’s methodological environment. Note, I would suggest the pressure of the economy would add the philosophy of lean to the mix yielding a three legged stool of the CMMI as a framework and Agile and lean philosophies as the implementation techniques.
If you step away from the model of change without involvement to embrace a more collaborative approach, a better solution will be generated, a solution yielding discipline, collaboration, effectiveness and efficiency. A solution that yields discipline, collaboration, effectiveness and efficiency. Focus is a good thing but consider focusing on involvement rather than on using focus as a tool to speak for others.
What fascinates me the most in the Lean software development approach is the quality of the people that support it. The Poppendieck are not an exception to this rule. Their book achieves the seemingly contradictory goals of being very insightful but still easy and captivating to read. It might be however easier to have the right flow when you are a Lean adept ;o)
The book starts with a chapter on systems thinking that takes also examples outside the software development world like Southwest Airlines. The next chapter on technical excellence is dedicated to a panorama of the software development approaches. Chapter 3 is kind of my favorite part of the book, extracting process management knowledge from the history of the construction of the Empire State Building, a project that took only one year to be completed. Chapter four presents the tools for improvement. Finally, the last part of the book is dedicated the people and leadership aspects of Lean.
The structure of the book makes it very pleasant to read, mixing the presentation of lean concepts with case studies and short personal stories. It is definitively a book that I will recommend to every software developer and manager…. and wish that every software developer and manager had read. Even if you think that Lean is not for you or you are a Toyota owner, this book provides a mind-opening text about what the values of software development and organizations should be.
Reference: “Leading Lean Software Development – Results are not the Point”, Mary and Tom Poppendieck, Addison-Wesley, 278 pages, IBSN 978-0-321-62070-5
Get more details on this book or buy it on amazon.com
Get more details on this book or buy it on amazon.co.uk



Yesterday I had a bit of an argument on Twitter about differences between Scrum and Kanban. Personally I don't care which is better than the other, because I believe that all models are wrong, but some are useful. And both Scrum and Kanban can be useful, given a certain context.
In yesterday's keynote speech at the Scrum Gathering in Orlando Jeff Sutherland said he had seen teams that were "doing Scrum" while they didn't even have a backlog. And there are reports of "Scrum teams" not practicing daily standup meetings, and teams not delivering a new product release every week.
These are not Scrum teams. They are ScrumBut teams. They do Scrum, *but* without some of the key ingredients.
Unfortunately, some people arguing against Scrum include these ScrumBut teams in their evaluations of the "high failure rate" of Scrum. They love quoting that "at least 75 percent of Scrum implementations fail." And I think "Yes of course, 75% fails when that includes the teams that don't understand what they're doing."
I believe that right now Kanban doesn't suffer from this problem. Kanban doesn't have a high failure rate because Kanban is still at the start of its adoption curve. Only very smart people like David Anderson and Karl Scotland are practicing it. And they know how to do it right!
But just wait a few years and see. When idiots like me get their hands on Kanban, we will start implementing KanbanButs, but we'll be calling it Kanban. We will have absolutely no idea what we're doing, because value stream mapping is not as simple as story point estimation. And we will introduce "Kanban teams" without limited WIP, or "Kanban teams" without a vizualized workflow.
Then the world will see a 75% failure rate of "Kanban" implementations.
And then there will be a great new software development method called Bonkiborki (which is the Mongolean word for 42). And I will have invented it. And it will have a much higher success rate than Scrum and Kanban, because I will be the only one who knows how to do it right.
(image by Misserion)
Twitter -
Subscribe -
Newsletter -
LinkedIn -
SlideShare
tweetmeme_url = 'http://www.noop.nl'; tweetmeme_source = 'jurgenappelo';
I recently came across 37 Signals 'Getting Real' book where they go through their approach to building web applications and there have certainly been some good reminders and ideas on the best way to do this.
These are some of my favourite parts:
If there are minor bugs, ship it as soon you have the core scenarios nailed and ship the bug fixes to web gradually after that. The faster you get the user feedback the better.
Often on projects I've worked on we've taken the approach that bugs get worked on before new stories which makes sense in a way because it means that we are fixing problems quickly and keeping the quality of the application high.
In reality what often happens is that low priority bugs just end up not getting looked at but I like the fact that we can choose to make that an explicit approach rather than just allowing it to happen to us.
Prioritize your bugs (and even ignore some of them)
Just because you discover a bug in your product, doesn’t mean it’s time to panic. All software has bugs – it’s just a fact of life.
I find it interesting that there might be more value in getting something out the door and then getting feedback on it rather than spending extra time perfecting it up front.
You have to figure out what’s really important. What’s going to make it into this initial release? This forces a constraint on you which will push you to make tough decisions instead of hemming and hawing.
From my experience a lot of times we end up implementing features just because that's what was agreed in the initial release plan and there is often a reluctance to change that even if a feature isn't really that useful anymore.
It becomes even more problematic if we get to the stage where it's not possible to deliver all the features promised in the remaining time so it certainly makes sense to me that in that situation we would look to focus on getting the absolutely essential things in first.
Sometimes the best way to know what your app should be is to know what it shouldn’t be. Figure out your app’s enemy and you’ll shine a light on where you need to go.
This seems to be a much better idea than just copying the ideas of your competitor which might seem the obvious thing to do if you're working in the same area.
The problem with that approach of course is that when you do copy you have no actual vision of what you're doing with your application anyway so you'll always be playing catch up.
There are a few parts of the book where the authors talk about keeping the application simple and then letting the users play with it:
The harder we tighten things down, the less room there is for a creative, emergent solution. Whether it’s locking down requirements before they are well understood or prematurely optimizing code, or inventing complex navigation and workflow scenarios before letting end users play with the system, the result is the same: an overly complicated, stupid system instead of a clean, elegant system that harnesses emergence.
Keep it small. Keep it simple. Let it happen.
Andrew Hunt, The Pragmatic Programmers
The users can then decide for us where we need to fill in more details:
Details reveal themselves as you use what you’re building. You’ll see what needs more attention. You’ll feel what’s missing. You’ll know which potholes to pave over because you’ll keep hitting them. That’s when you need to pay attention, not sooner.
In particular they suggest that focusing on very specific details about the page layout/colour/wording can be left until later because it will only serve to hinder forward progress if we concentrate on it too early.
You don’t have a scaling problem yet
“Will my app scale when millions of people start using it?”
Ya know what? Wait until that actually happens.
On several projects that I've worked on there often seems to be a desire to focus on performance and scaling an application very early on which seems wasteful when we could be focusing on actually building something that has so many users that we need to scale it later on. I think this advice is spot on.
A common theme throughout the book is that of writing less software to achieve our goals:
The best designers and the best programmers…are the ones that can determine what just doesn’t matter.
That’s where the real gains are made.
Most of the time you spend is wasted on things that just don’t matter. If you can cut out the work and thinking that just don’t matter, you’ll achieve productivity you’ve never imagined.
Innovation is not about saying yes to everything. It’s about saying NO to all but the most crucial features.
Throw away customer feature requests – if they're really important then they'll come back anyway
Don’t worry about tracking and saving each request that comes in. Let your customers be your memory. If it’s really worth remembering, they’ll remind you until you can’t forget.
The authors ideas around preferences were particularly interesting to me:
Preferences are also evil because they create more software.
More options require more code. And there’s all the extra testing and designing you need to do too.
I hadn't appreciated until recently quite how much complexity we can add to an application by allowing users to play around with the display of information on a screen.
It seems like a nice feature to have but it would be interesting to see statistics that could tell us what percentage of users actually that type of thing when it's not the core idea of the application.
I also quite liked the following and I think it's something that we need to do more often on teams:
Encourage programmers to make counteroffers.You want to hear: “The way you suggested will take 12 hours. But there’s a way I can do it that will only take one hour. It won’t do x but it will do y.” Let the software push back. Tell programmers to fight for what they think is the best way.
So don’t do the “paralysis through analysis” thing. That only slows progress and saps morale.
Instead, value the importance of moving on and moving forward. Get in the rhythm of making decisions. Make a quick, simple call and then go back and change that decision if it doesn’t work out.
I think a big part of this is getting the mentality that it's fine to make changes after we've 'finished' something. Any other approach doesn't work from my experience.
Meetings usually arise when a concept isn’t clear enough. Instead of resorting to a meeting, try to simplify the concept so you can discuss it quickly via email or im or Campfire.
I find it interesting that they prefer communicating by email because I've often found that it's not the best communication mechanism since it's really easy to misinterpret what people mean.
Having said that if we can make concepts clearer and the need for a meeting is an indicator that we need to do that then perhaps we can still meet in person and just make the meeting much shorter.
Too many apps start with a program-first mentality. That’s a bad idea. Programming is the heaviest component of building an app, meaning it’s the most expensive and hardest to change. Instead, start by designing first.
I've certainly fallen into this trap a lot but I've been trying to follow the outside in approach more strictly recently and so far I'm finding that it reduces the feedback cycle quite substantially which is only a good thing.
For each screen, you need to consider three possible states:
Regular
The screen people see when everything’s working fine and your app is flush with data.
Blank
The screen people see when using the app for the first time, before data is entered.
Error
The screen people see when something goes wrong.
I'd never even though of this at all and I'm certainly guilty of only ever considering applications when all the data is filled in so this is certainly something else to consider.
In the restaurant business, there’s a world of difference between those working in the kitchen and those out front who deal with customers. It’s important for both sides to understand and empathize with the other. That’s why cooking schools and restaurants will often have chefs work out front as waiters so the kitchen staff can interact with customers and see what it’s actually like on the front lines.
My colleague Chris Read and some others seem to be trying to close this gap with the devops movement which also has a track at QCon London this week.
The idea of working in support to see what an application is like from that perspective is something that more experienced colleagues often recommend although I've not done it as yet.
Overall I found this book a really interesting and quick read and although many of the ideas suggested seem like common sense it's strange that we often don't do all of them.
The 37 Signals guys also have a new book coming out in the UK tomorrow titled 'Rework' which sounds like it could be quite a good read as well.
The third release of the Android Native Development Kit (NDK) is now available for download from the Android developer site.
It can be used to target devices running Android 1.5 and higher. In addition to a few bug fixes and improvements, this release includes the following new features:
Toolchain improvementThe toolchain binaries have been refreshed for this release with GCC 4.4.0, which should generate slightly more compact and efficient machine code than the previous one (4.2.1).
Note that the GCC 4.4.0 C++ frontend is more pedantic, and may refuse to compile certain rare and invalid template declarations that were accepted by 4.2.1. To alleviate the problem, this NDK still provides the 4.2.1 binaries, which can optionally be used to build your machine code.
OpenGL ES 2.0 supportApplications targeting Android 2.0 (API level 5) or higher can now directly access OpenGL ES 2.0 features. This brings the ability to control graphics rendering through vertex and fragment shader programs, using the GLSL shading language.
A new trivial sample, named "hello-gl2", demonstrates how to render a simple triangle using both shader types.
Name simplificationThis NDK release is just called "r3", for "Revision 3", to indicate that it is not limited to a specific Android platform/API level. Some developers thought that the previous release's name (1.6_r1) was confusing and indicated that it could only be used to target Android 1.6, which was not true.
Enjoy!
Tuesday, March 9 marks the start of the 2010 Game Developers Conference in San Francisco, and Android will be there! There has been a lot of interest about Android from the game development community, and our presence at GDC is intended to provide developers everything they need to get started with the platform. We are hosting several technical sessions and participating in two industry panels.
We also want to meet you and answer your questions about Android game development, so we've set aside time for "office hours." Android team engineers will be on-hand to answer your questions, and if you have a game in development for Android, we'd love to see a demo.
Below, you can see the technical sessions that we're hosting and industry panels that we're participating in. We look forward to seeing you at GDC2010!
Technical sessionsTuesday, March 9Bootstrapping Games on Android
Chris Pruett
Everything you need to know about games on Android in 60 minutes.
1:45 PM - 2:45 PM
Room 309, South Hall
Bring Your Games to Android
Jack Palevich
An in-depth look at writing and porting C++ games using the NDK and a thin Java shell.
10:30 AM - 11:30 AM
Room 302, South Hall
Get the Most out of Android Media APIs
Dave Sparks & Jason Sams
Tips and tricks for optimizing your sound, video, and graphics for compatibility, efficiency, and battery life.
11:45 AM - 12:45 PM
Room 302, South Hall
Android Office Hours
The Android team
Come meet the team, ask us your questions, and show off your games!
3:00 PM - 4:00 PM
Room 302, South Hall
GamesBeat2010: A sea of mobile devices
Eric Chu
Industry experts weigh in on the future of mobile game development.
4:30 PM - 5:30 PM
Moscone Convention Center
After the iPhone...what?
Dave Sparks
Audio experts discuss the nitty gritty technical details of alternative gaming platforms.
10:30 AM - 11:30 AM
Room 112, North Hall
I recently posted some code that i asked you to review. When i posted it, the code had never even executed (that’s right, not even through a test) and i only thought it would do what i needed it to do. I consider the actual implementation non-obvious (at least for those who don’t know the copy-on-write approach to avoid traditional locking) so i just wanted to hear some reactions to the code from people who didn’t knew the context. I promised to do a follow-up post to discuss the code in its entirety so here it is.
First, i’ll show the whole class again:
public class TenantSessionFactoryManager : ITenantSessionFactoryManager
{
private readonly ITenantContext tenantContext;
private readonly ITenantInfoHolder tenantInfoHolder;
private readonly string mappingAssemblyName;
private readonly object writeLock = new object();
private Dictionary<Guid, ISessionFactory> sessionFactories;
public TenantSessionFactoryManager(ITenantContext tenantContext, ITenantInfoHolder tenantInfoHolder, string mappingAssemblyName)
{
this.tenantContext = tenantContext;
this.tenantInfoHolder = tenantInfoHolder;
this.mappingAssemblyName = mappingAssemblyName;
sessionFactories = new Dictionary<Guid, ISessionFactory>();
}
public ISession CreateSessionForCurrentTenant()
{
var tenantId = tenantContext.CurrentTenantId;
if (!sessionFactories.ContainsKey(tenantId))
{
CreateSessionFactoryForCurrentTenant();
}
return sessionFactories[tenantId].OpenSession();
}
private void CreateSessionFactoryForCurrentTenant()
{
lock (writeLock)
{
var tenantId = tenantContext.CurrentTenantId;
if (!sessionFactories.ContainsKey(tenantId))
{
var connectionString = tenantInfoHolder.GetDatabaseConnectionString(tenantId);
var sessionFactory = new Configuration()
.Configure()
.AddProperties(new Dictionary<string, string>
{
{ "connection.connection_string", connectionString },
{ "cache.region_prefix", "Tenant_" + tenantId }
})
.AddAssembly(mappingAssemblyName)
.BuildSessionFactory();
var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);
newDictionary[tenantId] = sessionFactory;
sessionFactories = newDictionary;
}
}
}
public void RemoveSessionFactoryForTenant(Guid tenantId)
{
if (!sessionFactories.ContainsKey(tenantId))
{
return;
}
lock (writeLock)
{
if (!sessionFactories.ContainsKey(tenantId))
{
return;
}
var sessionFactory = sessionFactories[tenantId];
var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);
newDictionary.Remove(tenantId);
sessionFactories = newDictionary;
sessionFactory.Dispose();
}
}
}
Basically, the purpose of this class is to hold a set of ISessionFactory instances, each of which belongs to a particular tenant in a multi-tenant application. Tenants can be added on the fly (without restarting the application) and when an ISessionFactory doesn’t exist yet for a particular tenant, it must be created when the first request for an ISession for that tenant comes in. Obviously, access to the sessionFactories dictionary must be thread-safe since multiple threads will be reading from the dictionary as well as occasionally writing to it.
I considered 3 options to make sure access to the dictionary would be thread-safe:
Traditional locking was quickly scratched from the list because that would require me to lock for every read of the dictionary as well as every write. Now, pretty much every single request requires an NHibernate session which means that pretty much every single request results in a lookup in the sessionFactories dictionary. If i need to lock for every read, this significantly hurts overall throughput of the system.
The ReadWriterLockSlim might be a good solution here… after all, the short description of this class in MSDN says this:
Represents a lock that is used to manage access to a resource, allowing multiple threads for reading or exclusive access for writing.
Sounds like what i need, right? But the thing is, i’ve never used the ReadWriterLockSlim class before and it hasn’t really gained my trust yet. I know that’s a terrible excuse for not using it, but here me out. While the ReadWriterLockSlim likely reduces locking overhead over traditional locking substantially, there still has to be some overhead for read operations, even if it is small. In most situations, that small overhead wouldn’t bother me but in this case, that little overhead would be added to pretty much every single request in the system. Now, writing to a dictionary implies that a new tenant has been added to the system. In the context of this system, that’s not even gonna happen on a daily basis. Hell, once a week is probably a best-case estimation and even that is highly optimistic. So i really don’t want any kind of overhead on read operations when the write operation is only going to happen very occasionally.
That leaves the copy-on-write pattern. I’ve used it before with success (though at the time, i didn’t know it was a known pattern) so this approach has already gained my trust. It basically implies that we don’t do any locking on the read operations, but whenever a write operation occurs we copy the original set of objects, perform the write on the newly copied set and then set the reference of the original set to the newly created and modified instance. During this whole time, every single read is safe. Successive reads within the same logical operation however aren’t, so the following code would not be thread-safe:
if (sessionFactories.ContainsKey(tenantId))
{
return sessionFactories[tenantId].OpenSession();
}
Because there’s no locking on the reads, the code within the if-block could fail because the sessionFactories reference could be pointing to a new dictionary which no longer contains the element for that key.
Of course, if you have frequent writes, the overhead of copying the set of objects every time you need to add/remove one might be bigger than you want, so this isn’t a pattern that you should use whenever you need to protect access to a shared resource. For this situation however, i think it’s ideal… though i’d obviously like to hear about better solutions
Now, let’s take a closer look at the pieces of code that perform the write operations. First, adding a new ISessionFactory to the dictionary:
private void CreateSessionFactoryForCurrentTenant()
{
lock (writeLock)
{
var tenantId = tenantContext.CurrentTenantId;
if (!sessionFactories.ContainsKey(tenantId))
{
var connectionString = tenantInfoHolder.GetDatabaseConnectionString(tenantId);
var sessionFactory = new Configuration()
.Configure()
.AddProperties(new Dictionary<string, string>
{
{ "connection.connection_string", connectionString },
{ "cache.region_prefix", "Tenant_" + tenantId }
})
.AddAssembly(mappingAssemblyName)
.BuildSessionFactory();
var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);
newDictionary[tenantId] = sessionFactory;
sessionFactories = newDictionary;
}
}
}
As you can see, the entire operation is put between a lock on the writeLock object instance. The downside of this is that creating an ISessionFactory instance is an expensive operation, which means the lock will be held for a long time (could easily be one or more seconds). Then again, i don’t anticipate this happening frequently so it’s not that big of an issue… especially since reads aren’t being blocked by this anyway. This approach also prevents the creation of 2 ISessionFactory instances for the same tenant. Well, unless i missed a bug here :p
Now, once the ISessionFactory instance is created, we create a new Dictionary based on the contents of the old one and then we add the new ISessionFactory instance to it. After that, we replace the sessionFactories references with the new dictionary and from that point on, every read will use the new dictionary instance. During this entire operation, no read operation was impacted negatively.
Now lets take a look at the other write operation, removing an ISessionFactory instance from the dictionary:
public void RemoveSessionFactoryForTenant(Guid tenantId)
{
if (!sessionFactories.ContainsKey(tenantId))
{
return;
}
lock (writeLock)
{
if (!sessionFactories.ContainsKey(tenantId))
{
return;
}
var sessionFactory = sessionFactories[tenantId];
var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);
newDictionary.Remove(tenantId);
sessionFactories = newDictionary;
sessionFactory.Dispose();
}
The first if-check, which happens outside of the lock is a bug that i missed but that was pointed out in the comments of the original post. If CreateSessionFactoryForCurrentTenant and RemoveSessionFactoryForTenant would execute concurrently for the same tenant, it’s possible that the ISessionFactory instance of that tenant is never removed from the dictionary (and also never disposed of…) since the check happens outside of the lock and could be executed before the ISessionFactory of the tenant was added to the dictionary. In that case, the ISessionFactory instance would stay in the dictionary as long as the application stays up. This is definitely a race condition that you want to avoid in every other situation though in this case, the odds that we’re simultaneously adding and removing the same tenant are slim to none. Nevertheless, i don’t want to be accused of promoting race conditions so we’ll make the change anyway
public void RemoveSessionFactoryForTenant(Guid tenantId)
{
lock (writeLock)
{
if (!sessionFactories.ContainsKey(tenantId))
{
return;
}
var sessionFactory = sessionFactories[tenantId];
var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);
newDictionary.Remove(tenantId);
sessionFactories = newDictionary;
sessionFactory.Dispose();
}
}
Now, as you can see we once again create a new dictionary based on the previous one, then remove the ISessionFactory instance for the current tenant and then we overwrite the sessionFactories instance once again.
Finally, there’s the read operation that i specifically didn’t want suffering from locking overhead:
public ISession CreateSessionForCurrentTenant()
{
var tenantId = tenantContext.CurrentTenantId;
if (!sessionFactories.ContainsKey(tenantId))
{
CreateSessionFactoryForCurrentTenant();
}
return sessionFactories[tenantId].OpenSession();
}
The only time this code will block is when a new ISessionFactory for the current tenant needs to be created. Luckily, that only happens once for each tenant. As i mentioned earlier in the post, using this pattern doesn’t guarantee that successive reads within the same logical operation are thread safe, so there is a bug in here. If a tenant already has an ISessionFactory instance, it’s possible that the RemoveSessionFactoryForTenant method has been executed between the if-check and accessing the ISessionFactory based on the tenantId. In that particular scenario, the ISessionFactory instance is no longer in the dictionary which will cause this code to throw an exception.
That’s a bug that i don’t feel like fixing though… Once a tenant has been removed, they are no longer a paying customer. If they are no longer paying for the software, there is no reason whatsoever why i should care about any possible exceptions they could get while running the software
Seriously though, if the RemoveSessionFactoryForTenant method is called, users of that tenant won’t even have access to the system anymore so it’s really a non-issue.
Anyways, i think i’ve covered the implementation in more detail than you probably cared for. So, any thoughts? Are there still issues that i haven’t thought of? Is there another approach that you would use for this specific scenario?
We’ve added two new tools for prioritizing a product backlog: Theme Screening and Theme Scoring. Each of these is a lightweight way of comparing product backlog items to one another.
Theme ScoringYou can use theme scoring to compare user stories or entire projects against one another. In this technique you identify a set of criteria that will be important in prioritizing. Each item is assessed on a relative 1-5 scale against each criterion and the priorities are determined.
![]()
Like theme scoring and relative weighting, this technique can be used to prioritize user stories or projects against one another. The simplest of the three prioritization techniques, theme screening starts with you identifying a baseline item. Each other item to be prioritized is compared to the baseline item for a set of factors that will determine priorities.
![]()