Quick Links

Hard and Soft Dependencies

One of my customers wanted a way to differentiate between mandatory and discretionary (or hard and soft) dependencies.

For my customer, the idea was that they wanted to be able to enter both hard and soft dependencies, and then implement and remove the soft logic links at their own discretion. So it gives them the ability to implement “what if” scenarios if the schedule got a little “tight”, allowing them to remove the soft dependencies effectively crashing the project.  Alas Project doesn’t allow use to add a flag to the dependency type, and so I figured the following work around.  Please note that this is in early developmental stages and so feel free to use this code; and if you improve on it, please let me know; and if you use it, please credit me (oh, and buy me a beer when you see me).

Step 1.

Create a text custom fields, called soft predecessor(s) unique ID using Text1; if you cannot use this field, choose another one and modify the VBA accordingly.  Note in the screen shot is shows that I have changed Text2 also; in the end I didn’t use this.


Step 2.

In your favourite table, add in the columns, unique ID and the Soft predecessor(s) unique ID.  We need to utilise the unique task ID, as the usual ID field can change when tasks are moved/inserted etc.  Typically I add these to the left of the predecessor column (which I typically move to the left of the task name anyway – the order isn’t important, but the visibility is).


Step 3.

Add the following VBA code into a module or macro in your favourite project client….  note that there are two proceduresAddSoftPredecessors and RemoveSoftPredecessors.  Their individual use should be fairly self explanatory.

Sub AddSoftPredecessors()
‘ 07/03/2014 Ben Howard – ben@applepark.co.uk www.applepark.co.uk/ben-howard-blog

Dim TskID1, TskID2, TskID3 As Long
Dim Tsks As Tasks
Dim Tsk As Task

Set Tsks = ActiveProject.Tasks

For Each Tsk In Tsks

‘ check to see if a task exists
If Not Tsk Is Nothing Then
‘ MsgBox (Tsk.Name)
‘ Tsk.Text2 = Tsk.UniqueIDPredecessors
‘ ConCatPreds = string   concat(tsk.UniqueIDPredecessors, tsk.Text1)
If Tsk.Text1 <> “” Then
‘ MsgBox (Tsk.Name & ” has a predecessor”)
‘ Tsk.Text2 = Tsk.UniqueIDPredecessors & “,” & Tsk.Text1
If Tsk.UniqueIDPredecessors <> “” Then
tempstr = Tsk.UniqueIDPredecessors & “,” & Tsk.Text1
tempstr = Tsk.Text1
‘ MsgBox (Tsk.Name & ” ” & tempstr)
End If
Tsk.UniqueIDPredecessors = tempstr
‘ MsgBox (Tsk.Name & ” has no predecessor”)
End If
End If
Next Tsk

End Sub

Sub RemoveSoftPredecessors()
‘ 07/03/2014 Ben Howard – ben@applepark.co.uk www.applepark.co.uk/ben-howard-blog

Dim Tsks As Tasks
Dim Tsk As Task

Set Tsks = ActiveProject.Tasks

For Each Tsk In Tsks

‘ check to see if a task exists
If Not Tsk Is Nothing Then
‘ check to see if we have both hard predecessors and soft predecessors
If (Tsk.UniqueIDPredecessors <> “”) And (Tsk.Text1 <> “”) Then
‘ MsgBox (Tsk.Name & ” has this chacter ” & Tsk.Text1 & ” at position ” & InStr(Tsk.UniqueIDPredecessors, Tsk.Text1) & ” in the Predecessors”)
If InStr(Tsk.UniqueIDPredecessors, Tsk.Text1) >= 0 Then
‘we know that some part of the string is matched
‘MsgBox (Tsk.Name & ” some match”)
‘MsgBox (“Unique Predecessor length of ” & Tsk.Name & “is ” & Len(Tsk.UniqueIDPredecessors))
‘Find out if the next character is a delimiter
nextchar = Mid(Tsk.UniqueIDPredecessors, InStr(Tsk.UniqueIDPredecessors, Tsk.Text1) + 1, 1)
‘ MsgBox (“next char ” & nextchar)
newstr = Replace(Tsk.UniqueIDPredecessors, Tsk.Text1 & nextchar, “”)
‘ check if there is a ‘ as the last character
If Len(newstr) > 0 And ((InStrRev(newstr, “,”) = Len(newstr))) Then
‘MsgBox (“we have a comma as the last char”)
newstr = Left(newstr, Len(newstr) – 1)
End If
‘MsgBox (“NewStr ” & newstr)
Tsk.UniqueIDPredecessors = newstr
‘MsgBox (Tsk.Name & ” no match”)
End If
‘ create a new string that removes duplicates from the two strings
End If
End If
Next Tsk

End Sub

Step 4.

Whilst we are playing around with adding the VBA/Macros, we might as well assign a couple of buttons to them in the ribbon.  I’ll just include the final screen shot here.  You can learn more on how to customise the ribbon in my newest book.


Step 5.

Enter your predecessors and dependencies as usually would.  These will become your “hard” predecessors.  Project schedules and accordingly based upon these dependencies and the existing constraints and task mode(s) within the project.  Notice that task T2 has hard predecessors of both T3 and T1.


Step 6.

Now comes the “fun” part.  In the schedule, for each task, enter the soft predecessor unique ID(s).  In the UK, these are separated by a comma; if your regional settings are different, you’ll need to modify the VBA.  For Task T3, I am going to create a “soft” predecessor of task T1.


Step 7.

To apply this “soft” dependency and see the effect on the schedule, click on the Add Soft Predecessors button to run the VBA.

Notice how the Unique ID Predecessor (the hard predecessor) of task T3 now equals the Soft predecessor ID, and the consequence that it this then has on the rest of the schedule (task t3 and Task T4 have both moved).


Step 8.

You can remove the effects of the soft dependency by clicking on the Remove Soft Predecessors button.

Enjoy,  Ben.


Share This Post
  1. Our ProjectPro Program Management Solution (PPMS) is able to create a set of dependencies in an automated way and can also remove them in an automated way. PPMS can be used to create these two scenarios of the schedule. If you need a commercial strength solution to do this what Ben describes, please contact us.

  2. Ben,

    Very good article. I’ve seen a couple of ways of handling soft dependencies, but this looks to be the best, especially if one is avoiding commercial solutions. I’m certainly going to be playing around with it.


    Jim Bressoud

  3. Logical dependencies are not likely to change, whereas discretionary dependencies are ephemeral. One such discretionary dependency is the “resource” dependency. It can be used to expose a resource critical path (RCP), especially after leveling. Critical Path Method (CPM) does not distinguish between logical and discretionary dependencies. Hence, CPM scheduling cannot identify RCP’s without the insertion of resource dependencies to remove phantom float.

    Ben’s article provides insight into how resource dependencies could be added and removed without destroying the “hard” logic of the network diagram.


Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Please complete this equation so we know you’re not a robot. *

Thanks for submitting your comment!
You must be logged in to comment.