Channels ▼


Generating Code Metrics and Estimating Costs with Xcode

Costs by Putnam

One of the earliest cost metrics is the Putnam cost model. This metric first appeared in 1978 in a seminal paper written by Lawrence Putnam. It assumes that project growth follows a Rayleigh distribution curve. The commercial package SLIM is based primarily on the Putnam model.

Figure 3 shows the three empirical equations of the Putnam cost model.

Figure 3.

Equation A computes the total effort Etot needed to complete the project. It expresses the effort in terms of person time, which may be in months or years. The constant Ktech is the technology index. It rates the project's dependence on current technology. The constant Kprod is the productivity index. It rates the productive quality of the team in terms of SLOC per unit time. The variable SLOC is, of course, the project size in effective lines of code. And the variable tproj is the desired time-to-market for the project. It uses the same person time units as Etot.

Equation B defines actual development (coding, design, etc.) as 39% of the total project effort. Equation C defines overall project difficulty as a ratio of development effort and time-to-market. Do not confuse this with Halstead difficulty, which measures code complexity.

Listing Two shows the Xcode utility script implementing the Putnam model. It begins with the path to the active project file (line 67). It uses that path to locate the enclosing project directory (lines 69-71). By definition, a project directory is the one with an xcodeproj bundle as one of its items. Checking for that bundle is handled by the utility routine isProject() (lines 52-62).

Listing Two

# -*- coding: utf-8 -*-
# import the following module
import os, sys
import string

# Count the number of effective source lines
def getELOC(aPth):
	# open an input stream
	tInp = open(aPth, 'r')
	# create the parse buffer
		tBuf = tInp.readlines()
	# start parsing the buffer
	tLOC = 0
	tBgn = False
	for tLin in tBuf:
		# filter out whitespaces
		tTst = tLin.strip()
		tLen = len(tTst)
		if (tLen > 0):
			# filter out inline comments
			tMrk = tTst.find("//", 0)
			if (tMrk != 0):
				tMrk = tTst.find("/*", 0)
				tMrk = tMrk + tTst.find("*/", 0)
				if (tMrk <= 0):
					# filter out import statements
					tMrk = tTst.find("#import", 0)
					if (tMrk != 0):
						# filter out block comments
						if (tBgn):
							# check for a closing token
							tMrk = tTst.find("*/", 0)
							tBgn = (tMrk == -1)
							# check for an opening token
							tMrk = tTst.find("/*", 0)
							tBgn = (tMrk >= 0)
							if (not tBgn):
								tLOC += 1
	# return the count results
	return (tLOC)

# Is this the main project directory?
def isProject(aPth):
	# get a list of files
	tLst = os.listdir(aPth)
	# parse the list
	tChk = False
	for tNom in tLst:
		tChk = tChk or (tNom.find(".xcodeproj") > 0)
	# return the check result
	return (tChk)

# locate the project directory
tPrj = '%%%{PBXFilePath}%%%'
tChk = False
while not(tChk):
	tPrj = os.path.dirname(tPrj)
	tChk = isProject(tPrj)

# parse the project directory
tSrc = []
for tRef, tDir, tLst in os.walk(tPrj):
	# parse the project files
	for tNom in tLst:
		tExt = string.split(tNom, ".")
		if (len(tExt) > 1):
			tExt = tExt[1]
			tChk = (tExt == "m") or (tExt == "h")
			if (tChk):
				tPth = os.path.join(tRef, tNom)

# calculate the project size
tSiz = 0
for tPth in tSrc:
	tSiz += getELOC(tPth)

# calculate the project costs
# -- PUTNAM:factor:productivity-index
kPI = 500

# -- PUTNAM:factor:technology-constant
kTech = 0.39

# -- PUTNAM:time:maximum-project
tTmax = 0.25

# --- PUTNAM:project:effort:total
tEtot = kTech * (tSiz ** 3.0)
tEtot = tEtot / ((kPI ** 3) * (tTmax ** 4))
print "Estimated total effort: %.3f" % tEtot

# --- PUTNAM:project:effort:development
tEdev = 0.3945 * tEtot
print "Estimated development effort: %.3f" % tEdev

# -- PUTNAM:project:difficulty
tDiff = tEdev / (tTmax ** 2)
print "Estimated project difficulty: %.3f" % tDiff

With project directory in hand, the script then parses all the files in that directory. It looks for files with a '.m' or '.h' suffix and adds them to the array buffer tSrc (lines 75-85). Then it counts the lines in each of the file (lines 88-90) using the method getELOC(). That method (lines 8-48) opens each file and counts only those lines it deemed effective. The resulting count is returned to the main script, which adds them to the variable tSiz.

Finally, the script computes the project's effort and difficulty. And it prints the results for the user to view (lines 103-113).

Calibrating the Putnam model involves choosing the right values to its two constants. For instance, consider the constant Ktech. Its possible values range from 0.1 to 1.0. A high Ktech value means the project is tech sensitive. It can be difficult and costly to adapt the project to a similar but incompatible technology. This is true of drivers that works only with certain hardware, or of video codecs that work exclusively with Apple QuickTime.

Conversely, a low Ktech value means the project is tech agnostic. Adapting it may require only minor rewrites and a rebuild. Some might need just a change of libraries or plug-ins. Low Ktech are typical of many open-source projects. For new projects with unknown dependencies, a value of 0.55 is a good starting point for Ktech.

As for Kprod, its possible values can range from 500 to 28000. Choosing the right value depends on the nature of the project and its team. For instance, a value of 500 means the team is performing below par. This could be due to poor work conditions, low morale, unrealistic demands, or ill-defined goals. It may be due to too many new hires, with their lack of practical experience. It may even be due to a start-up environment, with its uncertain future.

Next, a Kprod value of 2000 is typical of embedded or real-time projects. These projects have to contend with restricted and specific hardware resources. Code work is often exacting and terse, fine-tuned for a narrow range of tasks. Stringent testing is mandatory to ensure near transparent operation.

A Kprod value of 10000 is associated with telecom and system projects. They need to be flexible with hardware changes. Some scale well, showing improved performance and capacity with increases in hardware resources. Some use drivers to support new hardware. Some use discrete code libraries to factor out certain features.

Finally, Kprod values near 28000 are typical of commercial projects. These have high usability standards. They must anticipate every possible action a user might make. They must tolerate faults and guard against unexpected freezes or crashes. Some have to be hardware-agnostic, able to support a wide range of installed hardware. Others have to be system-agnostic, able to run on different host systems.

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.