Geek Noise
Rants, rambles, news and notes by Peter Provost
30

Call for Papers – The Architecture Journal

Monday, 30 November 2009 03:23 by Peter Provost
Arch_Journal_Logo

The Architecture Journal has just announce their call for papers for the 23rd issue, which just happens to be focusing on Architecture Modeling and its role in the broader SDLC.

If you’ve got something interesting you want to share, I encourage you to submit a paper idea and we’ll take a look. I’m helping review the submissions, so make it good! :)

More Info: http://msdn.microsoft.com/en-us/architecture/bb219087.aspx

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
10

Fun with PowerShell and TFS Work Items

Friday, 10 April 2009 06:53 by Peter Provost

It all started with me wanting a better burndown chart for my team. That was relatively simple to solve as we’ve got some pretty good ones floating around inside Microsoft. (Apologies in advance but I can’t share my spreadsheet with you at this time.)

Then came the fun… I wanted to be able to pull any given day’s “work done” and “work remaining” data. But for my own reasons, I don’t want this spreadsheet bound to the OLAP cube, I want to be able to mess with it.

Being the PowerShell junkie that I am I was pretty sure I could do this. I found James Manning’s killer “get-tfs.ps1” script which meant I didn’t have to work out that bit myself.

Using it is simple:

   1: $tfs = get-tfs http://mytfs:8080
   2: $wi = $tfs.wit.GetWorkItem(12345)

As you can see, I get the TFS client object via James’s script, and then I pull a WorkItem from it. From there I can ask the $wi object for all the bits of information in the work item. Piping it to get-member showed me the following methods and properties:

   1:  
   2:    TypeName: Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
   3:  
   4: Name                   MemberType            Definition                                                                
   5: ----                   ----------            ----------                                                                
   6: FieldChanged           Event                 Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemFieldChangeEve...
   7: Copy                   Method                Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem Copy(Microsof...
   8: Equals                 Method                bool Equals(System.Object obj)                                            
   9: GetHashCode            Method                int GetHashCode()                                                         
  10: GetNextState           Method                string GetNextState(string action)                                        
  11: GetType                Method                type GetType()                                                            
  12: IsValid                Method                bool IsValid()                                                            
  13: MergeToLatest          Method                System.Void MergeToLatest()                                               
  14: Open                   Method                System.Void Open()                                                        
  15: PartialOpen            Method                System.Void PartialOpen()                                                 
  16: Reset                  Method                System.Void Reset()                                                       
  17: Save                   Method                System.Void Save()                                                        
  18: SyncToLatest           Method                System.Void SyncToLatest()                                                
  19: ToString               Method                string ToString()                                                         
  20: Validate               Method                System.Collections.ArrayList Validate()                                   
  21: Item                   ParameterizedProperty System.Object Item(string name) {get;set;}, System.Object Item(Microsof...
  22: AreaId                 Property              System.Int32 AreaId {get;set;}                                            
  23: AreaPath               Property              System.String AreaPath {get;set;}                                         
  24: AttachedFileCount      Property              System.Int32 AttachedFileCount {get;}                                     
  25: Attachments            Property              Microsoft.TeamFoundation.WorkItemTracking.Client.AttachmentCollection A...
  26: ChangedBy              Property              System.String ChangedBy {get;}                                            
  27: ChangedDate            Property              System.DateTime ChangedDate {get;}                                        
  28: CreatedBy              Property              System.String CreatedBy {get;}                                            
  29: CreatedDate            Property              System.DateTime CreatedDate {get;}                                        
  30: Description            Property              System.String Description {get;set;}                                      
  31: DisplayForm            Property              System.String DisplayForm {get;}                                          
  32: ExternalLinkCount      Property              System.Int32 ExternalLinkCount {get;}                                     
  33: Fields                 Property              Microsoft.TeamFoundation.WorkItemTracking.Client.FieldCollection Fields...
  34: History                Property              System.String History {get;set;}                                          
  35: HyperLinkCount         Property              System.Int32 HyperLinkCount {get;}                                        
  36: Id                     Property              System.Int32 Id {get;}                                                    
  37: IsDirty                Property              System.Boolean IsDirty {get;}                                             
  38: IsNew                  Property              System.Boolean IsNew {get;}                                               
  39: IsOpen                 Property              System.Boolean IsOpen {get;}                                              
  40: IsPartialOpen          Property              System.Boolean IsPartialOpen {get;}                                       
  41: IsReadOnly             Property              System.Boolean IsReadOnly {get;}                                          
  42: IsReadOnlyOpen         Property              System.Boolean IsReadOnlyOpen {get;}                                      
  43: IterationId            Property              System.Int32 IterationId {get;set;}                                       
  44: IterationPath          Property              System.String IterationPath {get;set;}                                    
  45: Links                  Property              Microsoft.TeamFoundation.WorkItemTracking.Client.LinkCollection Links {...
  46: NodeName               Property              System.String NodeName {get;}                                             
  47: Project                Property              Microsoft.TeamFoundation.WorkItemTracking.Client.Project Project {get;}   
  48: Reason                 Property              System.String Reason {get;set;}                                           
  49: RelatedLinkCount       Property              System.Int32 RelatedLinkCount {get;}                                      
  50: Rev                    Property              System.Int32 Rev {get;}                                                   
  51: RevisedDate            Property              System.DateTime RevisedDate {get;}                                        
  52: Revision               Property              System.Int32 Revision {get;}                                              
  53: Revisions              Property              Microsoft.TeamFoundation.WorkItemTracking.Client.RevisionCollection Rev...
  54: State                  Property              System.String State {get;set;}                                            
  55: Store                  Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore Store {g...
  56: TemporaryId            Property              System.Int32 TemporaryId {get;}                                           
  57: Title                  Property              System.String Title {get;set;}                                            
  58: Type                   Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType Type {get;} 
  59: Uri                    Property              System.Uri Uri {get;}                                                     
  60: WorkItemLinkHistory    Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkCollection...
  61: WorkItemLinks          Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkCollection...
  62: GetCompletedWorkByDate ScriptMethod          System.Object GetCompletedWorkByDate();                                   
  63: GetRemainingWorkByDate ScriptMethod          System.Object GetRemainingWorkByDate();                                   

Lots of great stuff there, but what I really wanted was the work done on any given day and not the current work remaining. Hmmm…

After digging around in the object model (with PowerShell of course), I found the answer. The Revisions collection contains the full history of the Work Item. If I enumerated that, looking at the dates, I should be able to get what I want.

A little while later I had it all worked out, setup as a type extension in PowerShell so it automatically works with every WorkItem type I get. Type extensions are added via a special XML file (more info). Here’s what I added to mine:

   1: <Type>
   2:     <Name>Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem</Name>
   3:     <Members>
   4:         <ScriptMethod>
   5:             <Name>GetCompletedWorkByDate</Name>
   6:             <Script>
   1:  
   2:                 $date = [datetime] $args[0]
   3:                 $total = 0
   4:                 $this.Revisions | % {
   5:                     if ($_.Fields['Changed Date'].Value.Date -eq $date) {
   6:                         $work = $_.Fields["Completed Work"]
   7:                         if ($work -ne $null) { $total += ([int] $work.Value) - ([int] $work.OriginalValue) }
   8:                     }
   9:                 }
  10:                 return $total
  11:             
</Script>
   7:         </ScriptMethod>
   8:         <ScriptMethod>
   9:             <Name>GetRemainingWorkByDate</Name>
  10:             <Script>
   1:  
   2:                 $date = [datetime] $args[0]
   3:                 $total = 0
   4:                 $this.Revisions | % {
   5:                     if ($_.Fields['Changed Date'].Value.Date -le $date) {
   6:                         $work = $_.Fields["Remaining Work"]
   7:                         if ($work -ne $null) {
   8:                             $total = ([int] $work.Value)
   9:                         }
  10:                     }
  11:                 }
  12:                 return $total
  13:             
</Script>
  11:         </ScriptMethod>
  12:     </Members>
  13: </Type>

What this does is add two new methods to the .NET type Microsoft.TeamFoundation.WorkItemTracking.Client.Workitem. The first method takes a date and returns the sum of the “Completed Work” field for all revisions that occurred on that date. The second method enumerates the same Revisions collection, but this time it process all revisions up through the given date looking for the last one that says anything about the “Remaining Work” field.

Next step… create a script to wrap all this up into an easy to use command I call get-burndowndata.ps1:

   1: param( 
   2:         $deliverable = $(throw "Must provide deliverable ID"),
   3:         $date = [datetime]::Now.Date 
   4: )
   5:  
   6: $tfs = get-tfs http://mytfs:8080
   7: $deliverable = $tfs.WIT.GetWorkItem($deliverable) 
   8:  
   9: $result = @()
  10:  
  11: $deliverable.WorkItemLinks | ? { $_.LinkType.Name -eq "Child" } | % {
  12:     $feature = $tfs.WIT.GetWorkItem($_.TargetId)
  13:  
  14:     $feature.WorkItemLinks | ? { $_.LinkType.Name -eq "Child" } | % {
  15:         $task = $tfs.WIT.GetWorkItem($_.TargetId)
  16:         $completed = $task.GetCompletedWorkByDate($date)
  17:         $remaining = $task.GetRemainingWorkByDate($date)
  18:  
  19:         $obj = "" | select-object ID, Title, Completed, Remaining 
  20:         $obj.ID = $task.ID
  21:         $obj.Title = $task.Title
  22:         $obj.Completed = $completed
  23:         $obj.Remaining = $remaining
  24:  
  25:         $result += $obj
  26:     }
  27: }
  28:  
  29: $result

Now, getting any given day’s burndown information is as simple as calling that script and opening the result in Excel:

   1: get-burndowndata.ps1 12345 "4/1/2009" | export-csv data_20090401.csv
   2: invoke-item data_20090401.csv

Works like a charm!

Disclaimer: The get-burndowndata.ps1 script makes lots of assumptions about your TFS Work Item struction and relationships . It probably won’t work unmodified for anyone outside of DevDiv.

Currently rated 1.0 by 1 people

  • Currently 1/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
26

Elegant Code Interview

Monday, 26 January 2009 09:16 by Peter Provost

A few weeks ago I was invited by the folks over at Elegant Code to do an interview about myself, agile and the stuff I’m working on in VSTS. The podcast for that went live today:

http://elegantcode.com/2009/01/26/code-cast-19-peter-provost-on-agile-visual-studio-2010-and-architecture-tools/

Enjoy!

Currently rated 1.0 by 1920 people

  • Currently 1/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
07

Software Development Teams and Sports

Thursday, 7 August 2008 07:52 by Peter Provost

283716_1341 For a long time I’ve made the analogy that the best software development teams are like basketball or hockey teams, and lately I’ve been thinking more about how you can recognize what kind of a team you have by continuing this analogy and looking for similarities and differences.

In sports there are a few different kinds of teams. There are teams like gymnastics or bowling where the final result of a match is a result of the combined individual efforts of the team members, but the efforts of the team members aren’t combinatorial. In other words, on an Olympic gymnastics team, the team medal is awarded to the team who’s combined individual scores are the highest. On a bowling team, each player’s score is added together and the team with the highest total wins.

Another kind of sports team is the kind you see in American Pro Football. Here we have one team that is subdivided into two or three parts. The offense is a sub-team that works together to score points. The defense is another sub-team that works together to prevent the opposition from scoring points. There are other sub-teams for special activities like punt returns, field goals, etc.

Basketball, hockey, soccer and rugby are examples of yet another kind of team. On these teams the whole team is working together for the entire game to accomplish their task. There may be specialists on the team like goalies, defenders and wings who have focus areas, but if the time came for an offensive player to block a goal or even a goalie to shoot and score, they would do it.

The best functioning agile teams that I’ve worked with have been like that last kind of team. We have specialists who are good at certain things, but when the time comes to do some work, anyone and everyone does what needs to be done. We can talk all day about elimination of roles on agile teams, but we know from experience that the best testers are people with a natural bent for it. There are also people who are instinctive toolsmiths and will take small taxes that affect the team and mitigate them by adding script or a tool that benefits the whole team. But when it is time to signup for a task, or pair with someone, or fix the build server, or write a new test harness, everyone on the team is prepared and empowered to do that work.

I have also seen agile teams that are more like American Football teams. The most prominent indicator of this is a separation of developers (offense) from testers (defense). This can work, and a large number of teams work this way, but as with football, sometimes the defense finds itself with the ball and if they may not really know what to do with it. Or even worse, they may not feel empowered to do something with it.

You will also find that there are development teams that are more like gymnastic teams. Indicators of this are things like “class ownership” or "module ownership”. When you find architects who must design all the details before a developer can “code it up” you are likely seeing a gymnastics team. Almost any time you find architectural, design or process siloing, you are probably seeing one of these teams. As with gymnastics, these teams can be successful, but it creates a different culture than the one I’m a fan of.

One of the key differences between these types of teams is the attitude about work and dependencies between people. On a hockey or basketball team, the team must work together to win. You can put an amazing group of individuals together, but if they don’t play well together, they won’t win. Done well, the work is combinatorial, where the effort of one person improves the people around them and thereby improves the team. If someone falls down on the front line in a hockey game, you will be unsurprised when the defenseman continues forward and attacks the goal.

Each subteam on a football team behaves this way, but they can’t cross the boundaries very well. The people on the field are interdependent, but they are still siloed into certain responsibilities and expectations. Some might say that this is a result of the way the game is played, with each side taking turns, but in some college and most high-school football teams, the players play “both ways”, meaning that the same people play on both offense and defense. On those teams, when the ball is intercepted, you are much more likely to see the person with the ball being someone who knows how to run and/or throw.

On teams like gymnastics teams, though, you see something different. The person doing floor exercise goes and puts up a score, then the person doing parallel bars goes next, etc. One person can’t really help the next person other than by making a strong enough score to boost the overall team.

The next time you’re thinking about your team, about roles, about siloing and ownership, take a look around and think about what kind of team it is. Think about what kind of team you want. And think about what the forces are that are driving your team to be one way or another. You might be surprised what kind of team you’re on.

(Photo by jimmybop)

Currently rated 3.0 by 2 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
10

Scrum of Scrums Haiku

Thursday, 10 July 2008 06:05 by Peter Provost

Agility (Binshou) Kanji My Scrum of Scrums has
Become something other than
What I want it to be

It should be simply
A coming together of
Technical people

Instead it becomes
Like a management review
I lieu of sharing

What did you do since?
What will you do until we?
Is something blocking you?

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
08

Taking on dependencies from non-agile teams

Tuesday, 8 July 2008 03:58 by Peter Provost

After a spirited discussion this week on one of our internal agile aliases, Eric Gunnerson wrote a post on his blog that wraps up his thinking (and mine) about how to deal with taking dependencies on a non-agile team when your team is running in an agile manner:

Eric Gunnerson's C# Compendium : Taking on dependencies

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
30

Inherit to Be Reused, Not to Reuse

Monday, 30 June 2008 13:26 by Peter Provost

I'm surprised how often I have to say this to other developers and engineers, but violations of this simple object-oriented mantra seems to be everywhere. Almost every time I look at a class inheritance hierarchy, I find this principle violated.

Why is this use of inheritance bad? First of all, let's talk about what inheritance is good for:

  • Polymorphism - In OOP, this means that you can treat derived classes as if you had been passed an instance of the parent. This was formalized by Barbara Liskov in her 1988 paper "Data Abstraction and Hierarchy". Another way to say is is, "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it." [Martin-96]
  • Categorization - The process in which ideas and objects are recognized, differentiated and understood. Categorization implies that objects are grouped into categories, usually for some specific purpose. Ideally, a category illuminates a relationship between the subjects and objects of knowledge.

Let me refer you to the wonderful book, C++ Coding Standards: 101 Rules, Guidelines, and Best Practices by Herb Sutter and Andrei Alexandrescu:

Despite two decades of object-oriented design knowledge, the purpose and practice of public inheritance are still frequently misunderstood, and many uses of inheritance are flawed.

Public inheritance must always model "is-a" ("works-like-a") according to the Liskov Substitution Principle: All base contracts must be fulfilled, and so all overrides of virtual member functions must require no more and promise no less than their base versions if they are to successfully fulfill the base's contract. Code using a pointer or reference to a Base must behave correctly even when that pointer or reference actually points to a Derived.

...

Public inheritance is indeed about reuse, but not the way many programmers seem to think. As already pointed out, the purpose of public inheritance is to implement substitutability. The purpose of public inheritance is not for the derived class to reuse base class code to implement itself in terms of the base class's code. Such an is-implemented-in-terms-of relationship can be entirely proper, but should be modeled by composition—or, in special cases only, by nonpublic inheritance (see Item 34).

Let me call out one of the more importance sentences in that quote:

The purpose of public inheritance is not for the derived class to reuse base class code to implement itself in terms of the base class's code.

The inheritance relationship is one of the strongest coupling relationships we can have in OOP. Everyone knows that coupling is bad and cohesion is good, but we still couple like mad via inheritance. We do this for a number of reasons, but one of the big ones is that very few college grads seem to get taught this in school. It makes me wonder how many undergraduate compsci teachers actually get it. Daniel Pietraru wrote a bit about this and how he has used inheritance questions as interview questions.

The other reason I think it is so common is that our languages and tools make it look so easy and so proper. Even Fowler-esque Refactoring has refactorings called "Pull Up Method/Field/etc." that seem to be all about putting shared code into the base class. There is also the Abstract Test Pattern in TDD which specifically describes using base classes as "a way to reuse test cases".

Whenever possible, you should look to use composition instead of inheritance in your designs. The problem is that composition is harder to do, even though it results in cleaner more modular designs. Despite that, composition has a number of benefits over inheritance. Again, I'll let Messrs. Sutter and Alexandrescu tell it (remember that some of the techniques for pointers and such are very C/C++ centric and aren't relevant here, but the underlying meaning is still true):

Composition has important advantages over inheritance:

  • Greater flexibility without affecting calling code: A private data member is under your control. You can switch from holding it by value to holding by (smart) pointer or Pimpl (see Item 43) without breaking client code; you would only need to change the implementations of the class's own member functions that use it. If you decide you need different functionality, you can easily change the type of the member or the manner of holding it while keeping the class's public interface consistent. In contrast, if you begin with a public inheritance relationship, it is likely that clients have already come to depend on the inheritance; you have therefore committed your class to it and cannot easily change your base class decision later on.
  • Greater compile-time insulation, shorter compile times: Holding an object by pointer (preferably a smart pointer), rather than as a direct member or base class, can also allow you to reduce header dependencies because declaring a pointer to an object doesn't require that object's full class definition. By contrast, inheritance always requires the full definition of the base class to be visible. A common technique is to aggregate all private members behind a single opaque pointer, called a Pimpl.
  • Less weirdness: Inheriting from a type can cause name lookup to pull in functions and function templates defined in the same namespace as that type. This is very subtle and hard to debug.
  • Wider applicability: Some classes were not designed to be bases in the first place. Most classes, however, can fulfill the role of a member.
  • Great robustness and safety: The tighter coupling of inheritance makes it more difficult to write error-safe code.
  • Less complexity and fragility: Inheritance exposes you to additional complications, such as name hiding and other complications that can arise in the presence of later changes to the base class.

In essence, inheriting for code reuse makes your design brittle. Changes in strange places manifest themselves in even stranger places. If your language doesn't support multiple inheritance (like C# and Java), then if you use an form of class-based inheritance in your code, you are effectively preventing good Liskov-style inheritance by people who consume your code. Bad bad bad bad.

When you do use inheritance from a base class in your design, look for these gotchas:

  • Protected methods in the base class - This is the stink that is the smell that Herb talks about above.
  • Calling public methods in the base class from the derived class - Slightly less smelly, but still not good.

Honestly, it makes me want to try to eliminate all nonabstract inheritance in my code. In languages with good duck typing, I'd say eliminate inheritance entirely, because in those systems the only good reason to use inheritance is for derived class code reuse. I know this is an over aggressive reaction but I do wonder what our code would look like if we had good composition constructs in the language (we don't) and if we either went with pure duck typing (ala Ruby) or interface-only inheritance.

Like that's gonna happen...

Currently rated 4.0 by 4 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
27

Replacing ExpectedException in NUnit 2.4

Friday, 27 June 2008 06:14 by Peter Provost

Jim Newkirk, Brad Wilson and I have been in agreement about the evils of ExpectedException for a long time. When Jim and Brad wrote xUnit.net, in fact, they left it out and opted instead for a new Throws method that lets you be a lot more precise about what and when you are testing the exception.

But NUnit 2.4.x doesn't have this feature (2.5 will). Fear not! Jim has written a nice little sample of the Throws method for NUnit 2.4.x that provides this same experience in his new post Replacing ExpectedException in NUnit.

If you are using NUnit today, I would really suggest you read the post and consider changing the way you test exceptions in your unit tests.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   Agile Software Development
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed
29

Tracking Actual Work Done vs Estimated Work Remaining

Thursday, 29 May 2008 02:51 by Peter Provost

I see this get discussed all the time on some of the agile aliases I'm on.

I care how much time is left, not how much time you spent on it.

I know people like to talk about “using the data to make our estimating better” but there are flaws in that argument that just can’t be ignored:

  1. Nobody ever does it. In fact, I don’t even know of a process to achieve this. Hollering at people who over/under estimate is not an improvement process.
  2. It assumes you can make developer estimates better. More experienced developers estimate better, that I’ll take as a given, but can you accelerate this with novice/junior developers or testers? I don’t think so.
  3. Software is NOT like mechanical engineering. It is a craft. Every activity you do is very likely the first time you’ve done it exactly that way. So our inability to accurately and precisely estimate shouldn’t be all that surprising.

At least that’s how I see it. :)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
13

Simulated Agile Team Rooms

Tuesday, 13 May 2008 05:32 by Peter Provost

Today on an internal agile alias, a discussion came up about simulating agile team rooms for disbursed teams. I've played around with this for years and had some suggestions for them:


It can be simulated, but it is hard and requires extra discipline by the team. A few key things:

  1. Think about how to simulate the “in the room” experience where you can overhear and participate in conversations going on around you? Team void chat software like Ventrilo, Team Speak or our own Corporate Conference Calling system can work. Can you have an “open mic” in the team room? You also can give up on audio and use team room chat software like IRC. I’ve used them all. There are plusses and minuses to each.
  2. Think about the changes you may need to make to development practices. Do you use Pair-Programming and TDD? If so, you may want to take a look at Micro-pairing as a technique for coordinating the TDD/Pair handoffs. (Micro-pairing was actually created in response this exact scenario. I was pairing with another developer who was remote.)
  3. In addition to practice changes, think about how to deal with remote desktop sharing. Live Meeting works, but can be a bit heavy. Virtual Server and the standalone Virtual Server client actually let two people connect to the same desktop. I know that VNC, an open source remoting tool, also allows this, but I would recommend you to be cautious with that tool. It has some known security bugs and your network admins may not allow it. Check with them first.
  4. Make sure everyone on the team has all the necessary access they need to be a full team member. Access to version control, portals, file shares, email aliases, etc. all must be available.
  5. Think carefully about how you do your team meetings. When you have only 1 or 2 people who are remote and the rest of the team is in a room, the person on the far side WILL feel out of the loop unless you run the meeting as if everyone were remote. One thing I’ve heard of is to actually have everyone go into their individual offices and dial-in to the meeting so everyone is on an equal footing.
  6. Drastic time zone differences can make this very very hard on some team members. Ultimately this can be make-or-break for successful disbursed teaming. If people are 8 hours apart, when do you schedule standups and IP meetings? My rule of thumb is that more than 3-4 hours apart will kill you and you should split it into two teams that are closer in time to each other.

These are based on 3-4 years of playing around with these concepts at P&P. YMMV.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5