This entry describes the basis for hammock-type summary tasks and introduces an alternate method (and UpdateHammocks macro) for creating and maintaining such tasks in Microsoft Project (MSP) schedules.
Hammocks and LOE Tasks
“Hammock”* and “Level of Effort” (LOE) tasks in project schedules provide two similar approaches to summarizing and reporting the overall time consumed by a collection of other tasks. Typically, hammock or LOE tasks are used to represent the indirect management and other support activities associated with the primary tasks, and they are often loaded with management and other indirect resources. Hammock and LOE tasks are essentially the same, though minor differences exist in the implementation by different software. Since hammocks and LOE tasks do not possess any driving logic, they should be excluded from any formal definition of the Critical Path for the project.
* The “hammock” name refers to the simple method of suspending a sleeping net or cloth (i.e. the hammock) between two trees. When first described in hand-drawn activity-on-arrow (AOA) network diagrams, the time-summarizing activity took the shape of a simple curved line slung between two nodes – i.e. a hammock.
Hammocks in Primavera
Primavera scheduling tools have long provided explicit activity types for specifying hammock or LOE activities. Primavera Project Planner (P3) and Primavera SureTrak Project Manager, for example, both included specific hammock activity types that would be specially treated in the schedule calculations. The start dates for a hammock were defined by its Start-Start predecessors; finish dates came from its Finish-Finish successors; the same activity could not be included in both groups. Oracle’s Primavera P6, a newer application, allows for LOE activities that inherit their dates from the primary tasks that are included in their “predecessors” and “successors” lists. They are substantially more flexible than P3’s hammocks. In most respects the scheduling aspects of these LOE activities are similar to the scheduling of summary bars in P6 schedules (and summary tasks in MSP), with the key difference being that there is no need for common hierarchical structure or activity coding of the related primary activities.
Hammocks in Other Tools
Most other major project scheduling tools also have special-purpose hammock task types. For example, Phoenix Project Manager, Spider Project, and Deltek Open Plan all provide traditional hammock activity types, whose start and finish are defined by specific logical relationships. Asta PowerProject also includes a “hammock” task whose construction is more like that of an independent summary activity. That is, it is not necessary to indicate start/finish relationships. In general, the number of activities being summarized by the hammocks (or LOEs in P6) are not practically limited.
OLE Hammocks in MSP
MSP has never included an explicit Hammock or LOE task type, and since summary tasks do not provide the needed solution in many cases, a subtle method for constructing simple hammock tasks was created. As described here, the method involves copying the start/finish dates from two primary tasks and using a paste-special command to link these dates to the dates of the “hammock” task. The resulting “links” – based on common Windows OLE (object linking and embedding) technology rather than explicit logical schedule relationships – remain essentially hidden and cannot be easily described or audited in an MSP schedule.
MSP’s response to changes in the linked dates is similar to its response when dates are entered manually: i.e. it sets an early constraint (SNET or FNET) and adjusts the task duration so that the task spans between the two linked dates. Unfortunately, even if the links remain stable and updated (which is not guaranteed), the sources of these adjustments remain hidden.
MSP OLE Hammock Issues
In addition to the absence of auditable schedule information, regular users of linked hammocks may have noticed the following issues, which are present in MSP Professional 2010 and later releases:
- OLE hammocks are limited to summarizing only two tasks, one task providing the start date and the other providing the finish. This limitation seems most consistent with the original description of hammocks in AOA networks, but it doesn’t exist in other modern software. Often the activities being summarized are potentially concurrent, and it is preferred to allow the software to select dates from the group.
- MSP does not prevent the assignment of additional logical links or other constraints that may conflict with the OLE links.
- Creating new linked hammocks by copying and modifying existing linked hammocks – say as part of a fragnet replication – doesn’t work well. The resulting links may be subject to corruption and won’t update reliably. The only reliable way to create such links is to copy and paste-link them one-at-a-time.
- Even “automatic” updating of links sometimes fails, with repeated pounding of the F9 key having no affect. In these cases, it’s useful to open the Links window, select all the links, and force an update. (To open the window, the “Edit Links” command needs to be available on one of the ribbons. It can be added through the “customize the ribbon” dialog.) This tool is absolutely necessary to make OLE hammocks even slightly bearable.
- Resource leveling of linked hammocks can result in unintended consequences. Although most of these can be corrected by a forced update of the links, some changes require that the hammock task be reconstructed. E.g. removing leveling splits. The safest course is to assign a priority of 1000 to all linked hammock tasks, thereby exempting them from any leveling actions.
MSP Alternate Hammocks
An alternate approach to hammocks in MSP involves the following steps:
- Create the proposed hammock task as either a Fixed Units or Fixed Work task, depending on the nature of the resource loading required.
- Specify two predecessors to the proposed hammock task: one Start-to-Start and one Finish-to-Finish, without lags. (These are the same tasks that would otherwise be the sources of the Start and Finish paste-links. Here they are visible and auditable. Do Not paste links.)
- Avoid specifying any successors to the hammock.
- Create a custom flag field named “Hammock,” and assign a value of “Yes” to the Hammock flag for this task.
- Adjust the duration of the task such that it spans between the associated start and finish predecessor dates. (This is done automatically with the macro code below.)
- Ensure that the task is assigned a Priority of 1000, which prevents it from being resource-leveled. (This is done automatically with the macro code below.)
- Load indirect resources to the task as appropriate.
This alternate approach has the key benefit of presenting an explicit logical basis for the hammock task’s schedule dates, which can be easily checked and modified if necessary. It also supports the use of Fixed-Work hammocks for allocation of fixed contract costs. While this alternate approach is no more robust than OLE hammocks when summarizing tasks with potential concurrency, it is far easier to review, modify, and update the associated hammock links when the controlling activities change.
The macro/vba code below is intended to automatically update the durations of all hammock tasks in the active project. It also automatically removes constraints on hammocks and assigns a priority of 1000 to prevent resource leveling.
This macro/vba code comprises a subroutine and a custom function that should be pasted together into a single module in the Visual Basic Editor. The “UpdateHammocks” macro may then be assigned to a “hotkey” or ribbon command as appropriate.
[Edit March 2018. Our MSP add-in, BPC Logic Filter, excludes Hammocks constructed using this method from Longest-Path and Near-Longest-Path reports. This satisfies the requirement that such tasks not be included in any calculations of the project’s Critical Path. Since some users have reported inadvertent introduction of splits into hammock tasks during cost updating, I added a little mini-procedure to close all such splits that are 100% in the future, prior to updating the hammock duration. I also updated the duration calculator to accommodate an assigned resource with a non-standard calendar. ]
Sub UpdateHammocks() '15Sep'17 coded by TM Boyle, PSP. 'A code to routinely update the Durations of unlinked, user-managed "hammock" tasks in Microsoft Project. 'A "hammock" task is an indirect/support task that may be resource loaded. Its schedule 'depends solely on the tasks that it supports/summarizes. 'For this code to work: ' - All hammock tasks are coded using a custom Flag field (named "Hammock"); Alternately Flag1 is assumed. ' - Each hammock task has exactly one or two predecessors: ' - The "Start" predecessor has a Start-to-Start relationship with no lag ' - The "Finish" predecessor has a Finish-to-Finish relationship with no lag ' - If there is only one predecessor, then both start and finish of the hammock will come from it. ' - Each hammock should have NO successors, although this condition is not enforced. ' - Successors on the hammock can synthetically lengthen the backward path to its "Start" predecessor, ' thereby reducing Total Slack in that predecessor and its driving chain. '[21Mar'18 added code to remove splits in hammocks.] '[22Mar'18 added code for hammock scheduling using a single resource calendar.] Dim t As Task Dim d As TaskDependency Dim StartH As Date Dim FinishH As Date Dim i As Integer 'Added 21Mar'18 If Not HammockFieldExists Then MsgBox ("Couldn't find a Hammock Flag. Aborting") Exit Sub Else 'Proceed End If For Each t In ActiveProject.Tasks If Not t Is Nothing Then StartH = 0 FinishH = 0 If t.GetField(FieldNameToFieldConstant("Hammock")) = "Yes" Then 'If t.Flag1 = True Then 'Flag1 is used to designate Hammock Activities 'Added 21Mar'18 'First Close Splits if any On Error GoTo 0 If "Proceed" = "Proceed" Then '(change second "Proceed" to another word to bypass for troubleshooting) Do While t.SplitParts.Count > 1 i = t.SplitParts.Count 'Don't remove any splits that begin in the past If ActiveProject.StatusDate < ActiveProject.ProjectFinish Then 'StatusDate Exists If t.SplitParts(i - 1).Finish < ActiveProject.StatusDate Then Exit Do Else ' Use now date If t.SplitParts(i - 1).Finish < Now() Then Exit Do End If t.SplitParts(i).Start = t.SplitParts(i - 1).Finish Loop End If If t.PredecessorTasks.Count = 2 Or t.PredecessorTasks.Count = 1 Then For Each d In t.TaskDependencies If d.To = t Then If d.Type = pjFinishToStart Or d.Type = pjStartToFinish Then MsgBox ("Hammocks may only have SS or FF predecessors (Check predecessors): " & t.ID & " " & t.Name) Else If d.Type = pjStartToStart Then StartH = d.From.Start If d.Type = pjFinishToFinish Then FinishH = d.From.Finish If t.PredecessorTasks.Count = 1 Then If StartH = 0 Then StartH = d.From.Start If FinishH = 0 Then FinishH = d.From.Finish End If If d.Lag <> 0 Then MsgBox ("Hammocks should not have lag (Check lag): " & t.ID & " " & t.Name) End If Else MsgBox ("Hammocks should not have successors (Check successors): " & t.ID & " " & t.Name) End If Next d On Error Resume Next t.Duration = Application.DateDifference(StartH, FinishH, t.CalendarObject) If Err.Number <> 0 Then Err.Clear 'Added 22Mar'18 - allow for resource calendar controlling task schedule t.Duration = Application.DateDifference(StartH, FinishH, t.Assignments(1).Resource.Calendar) If Err.Number <> 0 Then Err.Clear t.Duration = Application.DateDifference(StartH, FinishH) If Err.Number <> 0 Then MsgBox ("Failed to update Hammock (Check predecessors): " & t.ID & " " & t.Name) End If End If End If If Err.Number = 0 Then t.Priority = 1000 t.ConstraintType = 0 End If Else MsgBox ("There must be 1 or 2 predecessors for this hammock activity. Not Updating: " & t.ID & " " & t.Name) End If End If End If Next t Application.CalculateProject End Sub Function HammockFieldExists() As Boolean Dim StrTest As String Dim FlagTemp As String StrTest = "Hammock" On Error Resume Next FlagTemp = ActiveProject.ProjectSummaryTask.GetField(FieldNameToFieldConstant(StrTest)) If Err.Number = 0 Then 'The fieldname exists and will be used HammockFieldExists = True Else HammockFieldExists = False End If End Function