Wednesday, January 6, 2010

Chapter 2. Implementing Integrated Process Improvement



[ Team LiB ]






Chapter 2. Implementing Integrated Process Improvement



Do what you can, with what you have, where you are.

�Theodore Roosevelt (1858�1919)



We find by experience (our own or another's) what is hurtful or helpful.

�Giovanni Battista Lamperti, Vocal Wisdom (1895)



I have but one lamp by which my feet are guided, and that is the lamp of experience.

�Patrick Henry, Speech before the Virginia Convention (1775)


The two questions that are most frequently raised at integrated process seminars and presentations are


How do I pull it all together?


and


What do I do with my existing process-improvement investments?


Both old hands and novices may be overwhelmed by what they see as the complexity of integrating their often-disparate process-improvement activities. This chapter presents some practical advice for implementing integrated process improvement. The advice is based on the experience of some of the Capability Maturity Model Integration (CMMI) authors and others who have used a variety of methods to integrate their process-improvement activities. The chapter doesn't attempt to summarize or repeat the information found in the wealth of process-improvement and change management books now available. Rather, it points out critical strategies that can facilitate process-improvement integration.


The first section of this chapter addresses the issues of starting a new process-improvement initiative in an integrated way. It is intended for organizations that have not yet implemented formal process improvement and hence will be starting out with a clean slate. Building the needed support systems, networks, and sponsors, and the way in which this activity differs from single-discipline process improvement, is addressed in the second section. The third section is intended for organizations that are currently pursuing process improvement. It suggests ways to incorporate legacy processes and current process-improvement initiatives into an integrated process-improvement structure, without losing the organization's existing investments. The fourth section focuses on the use of appraisals to provide encouragement and energy to the improvement process, without leading to a "checklist mentality." The fifth section looks at process-improvement activities that are not model-based, and that may be ongoing concurrently with CMMI in an organization. Finally, the sixth section presents lessons learned from several organizations in the form of "Pearls of Wisdom."






    [ Team LiB ]



    21.3 All-Pairs Shortest Paths



    [ Team LiB ]






    21.3 All-Pairs Shortest Paths


    In this section, we consider two classes that solve the all-pairs shortest-paths problem. The algorithms that we implement directly generalize two basic algorithms that we considered in Section 19.3 for the transitive-closure problem. The first method is to run Dijkstra's algorithm from each vertex to get the shortest paths from that vertex to each of the others. If we implement the priority queue with a heap, the worst-case running time for this approach is proportional to VE lg V, and we can improve this bound to VE for many types of networks by using a d-ary heap. The second method, which allows us to solve the problem directly in time proportional to V3, is an extension of Warshall's algorithm that is known as Floyd's algorithm.


    Both of these classes implement an abstract�shortest-paths ADT interface for finding shortest distances and paths. This interface, which is shown in Program 21.2, is a generalization to weighted digraphs of the abstract�transitive-closure interface for connectivity queries in digraphs that we studied in Chapter 19. In both class implementations, the constructor solves the all-pairs shortest-paths problem and saves the result in private data fields to support query methods that return the shortest-path length from one given vertex to another and either the first or last edge on the path. Implementing such an ADT is a primary reason to use all-pairs shortest-paths algorithms in practice.


    Program 21.3 is a sample client program that uses the all-pairs shortest-paths ADT interface to find the weighted diameter of a network. It checks all pairs of vertices to find the one for which the shortest-path length is longest; then, it traverses the path, edge by edge. Figure 21.13 shows the path computed by this program for our Euclidean network example.



    Figure 21.13. Diameter of a network

    The largest entry in a network's all-shortest-paths matrix is the diameter of the network: the length of the longest of the shortest paths, depicted here for our sample Euclidean network.







    The goal of the algorithms in this section is to support constant-time implementations of the query methods. Typically, we expect to have a huge number of such requests, so we are willing to invest substantial resources in private data fields and preprocessing in the constructor to be able to answer the queries quickly. Both of the algorithms that we consider use space proportional to V2 for the private data fields.


    The primary disadvantage of this general approach is that, for a huge network, we may not have so much space available (or we might not be able to afford the requisite preprocessing time). In principle, our interface provides us with the latitude to trade off preprocessing time and space for query time. If we expect only a few queries, we can do no preprocessing and simply run a single-source algorithm for each query, but intermediate situations require more advanced algorithms (see Exercises 21.48 through 21.50). This problem generalizes one that challenged us for much of Chapter 19: the problem of supporting fast reachability queries in limited space.



    Program 21.2 All-pairs shortest-paths ADT


    Our solutions to the all-pairs shortest-paths problem are all classes with a constructor and two query methods: a dist method that returns the length of the shortest path from the first given vertex to the second; and one of two possible path methods, either path, which returns a reference to the first edge on the shortest path, or pathR, which returns a reference to the final edge on the shortest path. If there is no such path, the path method returns 0 and dist is undefined.


    We use path or pathR as convenient for the algorithm under scrutiny; in practice, we might need to settle upon one or the other (or both) in the interface and use various transfer functions in implementations, as discussed in Section 21.1 and in the exercises at the end of this section.





    class GraphSPall // ADT interface
    { // implementations and private members hidden
    GraphSPall(GRAPH G)
    Edge path(int, int)
    Edge pathR(int, int)
    double dist(int, int)
    }




    The first all-pairs shortest-paths ADT method implementation that we consider solves the problem by using Dijkstra's algorithm to solve the single-source problem for each vertex. In Java, we can express the method directly, as shown in Program 21.4: We build an array of GraphSPT objects, one to solve the single-source problem for each vertex. This method generalizes the BFS-based method for unweighted undirected graphs that we considered in Section 17.7. It is also similar to our use of a DFS that starts at each vertex to compute the transitive closure of unweighted digraphs, in Program 19.4.



    Program 21.3 Computing the diameter of a network


    This client illustrates the use of the interface in Program 21.2. It finds the longest of the shortest paths in the given network, prints the path, and returns its weight (the diameter of the network).





    static double diameter(Graph G)
    { int vmax = 0, wmax = 0;
    GraphSPall all = new GraphSPall(G);
    for (int v = 0; v < G.V(); v++)
    for (int w = 0; w < G.V(); w++)
    if (all.path(v, w) != null)
    if (all.dist(v, w) > all.dist(vmax, wmax))
    { vmax = v; wmax = w; }
    int v = vmax; Out.print(v + "");
    while (v != wmax)
    { v = all.path(v, wmax).w(); Out.print("-" + v); }
    return all.dist(vmax, wmax);
    }




    Property 21.7



    With Dijkstra's algorithm, we can find all shortest paths in a network that has nonnegative weights in time proportional to VE logd V, where d = 2 if E < 2 V, and d = E/V otherwise.


    Proof: Immediate from Property 21.6.




    As are our bounds for the single-source shortest-paths and the MST problems, this bound is conservative; a running time of VE is likely for typical graphs.


    To compare this implementation with others, it is useful to study the matrices implicit in the array-of-arrays structure of the private data fields. The wt arrays form precisely the distances matrix that we considered in Section 21.1: The entry in row s and column t is the length of the shortest path from s to t. As illustrated in Figures 21.8 and 21.9, the spt arrays form the transpose of the paths matrix: The entry in row s and column t is the last entry on the shortest path from s to t.


    For dense graphs, we could use an adjacency-matrix representation and avoid computing the reverse graph by implicitly transposing the matrix (interchanging the row and column indices), as in Program 19.7. Developing an implementation along these lines is an interesting programming exercise and leads to a compact implementation (see Exercise 21.43); however, a different approach, which we consider next, admits an even more compact implementation.



    Program 21.4 Dijkstra's algorithm for all shortest paths


    This class uses Dijkstra's algorithm to build an SPT for each vertex so that it can answer pathR and dist queries for any pair of vertices.





    class GraphSPall
    { private GraphSPT[] A;
    GraphSPall(Graph G)
    {
    A = new GraphSPT[G.V()];
    for (int v = 0; v < G.V(); v++)
    A[v] = new GraphSPT(G, v);
    }
    Edge pathR(int s, int t)
    { return A[s].pathR(t); }
    double dist(int s, int t)
    { return A[s].dist(t); }
    }




    The method of choice for solving the all-pairs shortest-paths problem in dense graphs, which was developed by R. Floyd, is precisely the same as Warshall's method, except that instead of using the logical or operation to keep track of the existence of paths, it checks distances for each edge to determine whether that edge is part of a new shorter path. Indeed, as we have noted, Floyd's and Warshall's algorithms are identical in the proper abstract setting (see Sections 19.3 and 21.1).


    Program 21.5 is an all-pairs shortest-paths ADT implementation that uses Floyd's algorithm. It explictly uses the matrices from Section 21.1 as private data fields: a V-by-V array of arrays d for the distances matrix, and another V-by-V array of arrays p for the paths table. For every pair of vertices s and t, the constructor sets d[s][t] to the shortest-path length from s to t (to be returned by the dist method) and p[s][t] to the index of the next vertex on the shortest path from s to t (to be returned by the path method). The implementation is based upon the path relaxation operation that we considered in Section 21.1.



    Program 21.5 Floyd's algorithm for all shortest paths


    This implementation of the interface in Program 21.2 uses Floyd's algorithm, a generalization of Warshall's algorithm (see Program 19.3) that finds the shortest paths between each pair of points instead of just testing for their existence.


    After initializing the distances and paths matrices with the graph's edges, we do a series of relaxation operations to compute the shortest paths. The algorithm is simple to implement, but verifying that it computes the shortest paths is more complicated (see text).





    class GraphSPall
    { private Edge[][] p;
    private double[][] d;
    GraphSPall(Graph G)
    { int V = G.V();
    p = new Edge[V][V]; d = new double[V][V];
    for (int s = 0; s < V; s++)
    for (int t = 0; t < V; t++)
    d[s][t] = maxWT;
    for (int s = 0; s < V; s++)
    for (int t = 0; t < V; t++)
    if (G.edge(s, t) != null)
    { p[s][t] = G.edge(s, t);
    d[s][t] = G.edge(s, t).wt(); }
    for (int s = 0; s < V; s++) d[s][s] = 0.0;
    for (int i = 0; i < V; i++)
    for (int s = 0; s < V; s++)
    if (p[s][i] != null)
    for (int t = 0; t < V; t++)
    if (s != t)
    if (d[s][t] > d[s][i] + d[i][t])
    { p[s][t] = p[s][i];
    d[s][t] = d[s][i] + d[i][t]; }
    }
    Edge path(int s, int t)
    { return p[s][t]; }
    double dist(int s, int t)
    { return d[s][t]; }
    }




    Property 21.8



    With Floyd's algorithm, we can find all shortest paths in a network in time proportional to V3.


    Proof: The running time is immediate from inspection of the code. We prove that the algorithm is correct by induction in precisely the same way as we did for Warshall's algorithm. The ith iteration of the loop computes a shortest path from s to t in the network that does not include any vertices with indices greater than i (except possibly the endpoints s and t). Assuming this fact to be true for the ith iteration of the loop, we prove it to be true for the (i+1)st iteration of the loop. A shortest path from s to t that does not include any vertices with indices greater than i+1 is either (i) a path from s to t that does not include any vertices with indices greater than i, of length d[s][t], that was found on a previous iteration of the loop, by the inductive hypothesis; or (ii) comprising a path from s to i and a path from i to t, neither of which includes any vertices with indices greater than i, in which case the inner loop sets d[s][t].




    Figure 21.14 is a detailed trace of Floyd's algorithm on our sample network. If we convert each blank entry to 0 (to indicate the absence of an edge) and convert each nonblank entry to 1 (to indicate the presence of an edge), then these matrices describe the operation of Warshall's algorithm in precisely the same manner as we did in Figure 19.15. For Floyd's algorithm, the nonblank entries indicate more than the existence of a path; they give information about the shortest known path. An entry in the distance matrix has the length of the shortest known path connecting the vertices corresponding to the given row and column; the corresponding entry in the paths matrix gives the next vertex on that path. As the matrices become filled with nonblank entries, running Warshall's algorithm amounts to just double-checking that new paths connect pairs of vertices already known to be connected by a path; in contrast, Floyd's algorithm must compare (and update if necessary) each new path to see whether the new path leads to shorter paths.



    Figure 21.14. Floyd's algorithm

    This sequence shows the construction of the all-pairs shortest-paths matrices with Floyd's algorithm. For i from 0 to 5 (top to bottom), we consider, for all s and t, all of the paths from s to t having no intermediate vertices greater than i (the shaded vertices). Initially, the only such paths are the network's edges, so the distances matrix (center) is the graph's adjacency matrix and the paths matrix (right) is set with p[s][t] = t for each edge s-t. For vertex 0 (top), the algorithm finds that 3-0-1 is shorter than the sentinel value that is present because there is no edge 3-1 and updates the matrices accordingly. It does not do so for paths such as 3-0-5, which is not shorter than the known path 3-5. Next the algorithm considers paths through 0 and 1 (second from top) and finds the new shorter paths 0-1-2, 0-1-4, 3-0-1-2, 3-0-1-4, and 5-1-2. The third row from the top shows the updates corresponding to shorter paths through 0, 1, and 2 and so forth.

    Black numbers overstriking gray ones in the matrices indicate situations where the algorithm finds a shorter path than one it found earlier. For example, .91 overstrikes 1.37 in row 3 and column 2 in the bottom diagram because the algorithm discovered that 3-5-4-2 is shorter than 3-0-1-2.







    Comparing the worst-case bounds on the running times of Dijkstra's and Floyd's algorithms, we can draw the same conclusion for these all-pairs shortest-paths algorithms as we did for the corresponding transitive-closure algorithms in Section 19.3. Running Dijkstra's algorithm on each vertex is clearly the method of choice for sparse networks, because the running time is close to VE. As density increases, Floyd's algorithm�which always takes time proportional to V3�becomes competitive (see Exercise 21.67); it is widely used because it is so simple to implement.


    A more fundamental distinction between the algorithms, which we examine in detail in Section 21.7, is that Floyd's algorithm is effective in even those networks that have negative weights (provided that there are no negative cycles). As we noted in Section 21.2, Dijkstra's method does not necessarily find shortest paths in such graphs.


    The classical solutions to the all-pairs shortest-paths problem that we have described presume that we have space available to hold the distances and paths matrices. Huge sparse graphs, where we cannot afford to have any V-by-V matrices, present another set of challenging and interesting problems. As we saw in Chapter 19, it is an open problem to reduce this space cost to be proportional to V while still supporting constant-time shortest-path-length queries. We found the analogous problem to be difficult even for the simpler reachability problem (where we are satisfied with learning in constant time whether there is any path connecting a given pair of vertices), so we cannot expect a simple solution for the all-pairs shortest-paths problem. Indeed, the number of different shortest path lengths is, in general, proportional to V2 even for sparse graphs. That value, in some sense, measures the amount of information that we need to process and perhaps indicates that when we do have restrictions on space, we must expect to spend more time on each query (see Exercises 21.48 through 21.50).



    Exercises


    21.39 Estimate, to within a factor of 10, the largest graph (measured by its number of vertices) that your computer and programming system could handle if you were to use Floyd's algorithm to compute all its shortest paths in 10 seconds.

    21.40 Estimate, to within a factor of 10, the largest graph of density 10 (measured by its number of edges) that your computer and programming system could handle if you were to use Dijkstra's algorithm to compute all its shortest paths in 10 seconds.

    21.41 Show, in the style of Figure 21.9, the result of using Dijkstra's algorithm to compute all shortest paths of the network defined in Exercise 21.1.

    21.42 Show, in the style of Figure 21.14, the result of using Floyd's algorithm to compute all shortest paths of the network defined in Exercise 21.1.

    21.43 Combine Program 20.6 and Program 21.4 to make an implementation of the all-pairs shortest-paths ADT interface (based on Dijkstra's algorithm) for dense networks that supports path queries but does not explicitly compute the reverse network. Do not define a separate method for the single-source solution�put the code from Program 20.6 directly in the inner loop, and put results directly in private data fields d and p like those in Program 21.5).

    21.44 Run empirical tests, in the style of Table 20.2, to compare Dijkstra's algorithm (Program 21.4 and Exercise 21.43) and Floyd's algorithm (Program 21.5) for various networks (see Exercises 21.4�8).

    21.45 Run empirical tests to determine the number of times that Floyd's and Dijkstra's algorithms update the values in the distances matrix for various networks (see Exercises 21.4�8).

    21.46 Give a matrix in which the entry in row s and column t is equal to the number of different simple directed paths connecting s and t in Figure 21.1.

    21.47 Implement a class whose constructor computes the path-count matrix that is described in Exercise 21.46 so that it can provide count queries through a query method in constant time.

    21.48 Develop a class implementation of the abstract�shortest-paths ADT for sparse graphs that cuts the space cost to be proportional to V by increasing the query time to be proportional to V.

    • 21.49 Develop a class implementation of the abstract�shortest-paths ADT for sparse graphs that uses substantially less than O(V2) space but supports queries in substantially less than O(V) time. Hint: Compute all shortest paths for a subset of the vertices.

    21.50 Develop a class implementation of the abstract�shortest-paths ADT for sparse graphs that uses substantially less than O(V2) space and (using randomization) supports queries in constant expected time.

    21.51 Develop a class implementation of the abstract�shortest-paths ADT that takes the lazy approach of using Dijkstra's algorithm to build the SPT (and associated distance array) for each vertex s the first time that the client issues a shortest-path query from s, then references the information on subsequent queries.

    21.52 Modify the shortest-paths ADT and Dijkstra's algorithm to handle shortest-paths computations in networks that have weights on both vertices and edges. Do not rebuild the graph representation (the method described in Exercise 21.4); modify the code instead.

    • 21.53 Build a small model of airline routes and connection times, perhaps based upon some flights that you have taken. Use your solution to Exercise 21.52 to compute the fastest way to get from one of the served destinations to another. Then test your program on real data (see Exercise 21.5).







      [ Team LiB ]



      Main Page



      [ Team LiB ]





        
      • Table of Contents
      Algorithms in Java, Third Edition, Part 5: Graph Algorithms
      By
      Robert Sedgewick
       
      Publisher: Addison Wesley
      Pub Date: July 15, 2003
      ISBN: 0-201-36121-3
      Pages: 528



      Once again, Robert Sedgewick provides a current and comprehensive introduction to important algorithms. The focus this time is on graph algorithms, which are increasingly critical for a wide range of applications, such as network connectivity, circuit design, scheduling, transaction processing, and resource allocation. In this book, Sedgewick offers the same successful blend of theory and practice that has made his work popular with programmers for many years. Michael Schidlowsky and Sedgewick have developed concise new Java implementations that both express the methods in a natural and direct manner and also can be used in real applications.



      Algorithms in Java, Third Edition, Part 5: Graph Algorithms is the second book in Sedgewick's thoroughly revised and rewritten series. The first book, Parts 1-4, addresses fundamental algorithms, data structures, sorting, and searching. A forthcoming third book will focus on strings, geometry, and a range of advanced algorithms. Each book's expanded coverage features new algorithms and implementations, enhanced descriptions and diagrams, and a wealth of new exercises for polishing skills. The natural match between Java classes and abstract data type (ADT) implementations makes the code more broadly useful and relevant for the modern object-oriented programming environment.


      The Web site for this book (www.cs.princeton.edu/~rs/) provides additional source code for programmers along with a variety of academic support materials for educators.


      Coverage includes:

      • A complete overview of graph properties and types

      • Diagraphs and DAGs

      • Minimum spanning trees

      • Shortest paths

      • Network flows

      • Diagrams, sample Java code, and detailed algorithm descriptions



      A landmark revision, Algorithms in Java, Third Edition, Part 5 provides a complete tool set for programmers to implement, debug, and use graph algorithms across a wide range of computer applications.





      [ Team LiB ]



      Puzzle 13: Animal Farm











       < Day Day Up > 







      Puzzle 13: Animal Farm



      Readers of George Orwell's Animal Farm may remember old Major's pronouncement that "all animals are equal." The following Java program attempts to test this pronouncement. What does it print?





      public class AnimalFarm {

      public static void main(String[] args) {

      final String pig = "length: 10";

      final String dog = "length: " + pig.length();

      System.out.println("Animals are equal: "

      + pig == dog);

      }

      }






      Solution 13: Animal Farm



      A superficial analysis of the program might suggest that it should print Animals are equal: true. After all, pig and dog are both final String variables initialized to the character sequence "length: 10". In other words, the strings referred to by pig and dog are and will forever remain equal to each other. The == operator, however, does not test whether two objects are equal; it tests whether two object references are identical. In other words, it tests whether they refer to precisely the same object. In this case, they do not.



      You may be aware that compile-time constants of type String are interned [JLS 15.28]. In other words, any two constant expressions of type String that designate the same character sequence are represented by identical object references. If initialized with constant expressions, both pig and dog would indeed refer to the same object, but dog is not initialized with a constant expression. The language constrains which operations are permitted to appear in a constant expression [JLS 16.28], and method invocation is not among them. Therefore the program should print Animals are equal: false, right?



      Well, no, actually. If you ran the program, you found that it prints false and nothing else. It doesn't print Animals are equal: . How could it not print this string literal, which is right there in black and white? The solution to Puzzle 11 contains a hint: The + operator, whether used for addition or string concatenation, binds more tightly than the == operator. Therefore, the parameter of the println method is evaluated like this:



      System.out.println(("Animals are equal: " + pig) == dog);



      The value of the boolean expression is, of course, false, and that is exactly what the program prints. There is one surefire way to avoid this sort of difficulty: When using the string concatenation operator, always parenthesize nontrivial operands. More generally, when you are not sure whether you need parentheses, err on the side of caution and include them. If you parenthesize the comparison in the println statement as follows, it will produce the expected output of Animals are equal: false:



      System.out.println("Animals are equal: " + (pig == dog));



      Arguably, the program is still broken. Your code should rarely, if ever, depend on the interning of string constants. Interning was designed solely to reduce the memory footprint of the virtual machine, not as a tool for programmers. As this puzzle demonstrates, it isn't always obvious which expressions will result in string constants. Worse, if your code depends on interning for its correct operation, you must carefully keep track of which fields and parameters must be interned. The compiler can't check these invariants for you, because interned and noninterned strings are represented by the same type (String). The bugs that result from the failure to intern a string are typically quite difficult to detect.



      When comparing object references, you should use the equals method in preference to the == operator unless you need to compare object identity rather than value. Applying this lesson to our program, here is how the println statement should look. It is clear that the program prints TRue when it is fixed in this fashion:



      System.out.println("Animals are equal: " + pig.equals(dog));



      This puzzle has two lessons for language designers. The natural precedence of string concatenation might not be the same as that of addition. This implies that it is problematic to overload the + operator to perform string concatenation, as mentioned in Puzzle 11. Also, reference equality is more confusing than value equality for immutable types, such as String. Perhaps the == operator should perform value comparisons when applied to immutable reference types. One way to achieve this would be to make the == operator a shorthand for the equals method, and to provide a separate method to perform reference identity comparison, akin to System.identityHashCode.

















         < Day Day Up > 



        Program 1: Hello World













        Program 1: Hello World

        "Hello World" seems to be the first program in almost every programming book, and this is no different. But this one is broken.


        How can you break something as simple as "Hello World"? Take a look and see:




        1 /************************************************
        2 * The "standard" hello world program. *
        3 *************************************************/
        4 #include <iostream>
        5
        6 void main(void)
        7 {
        8 std::cout << "Hello world!\n";
        9 }


        (Next Hint 228. Answer 6.)




















        Section 6.1. A Brief History of HTML










        6.1. A Brief History
        of HTML



        HTML 1.02.0

        HTML 3

        HTML 4

        These were the early days; you could fit everything there was to know about HTML into the back of your car. Pages weren't pretty, but at least they were hypertext enabled. No one cared much about presentation, and just about everyone on the Web had their very own "home page." Even a count of the number of pencils, paperclips, and Post-it notes on your desk was considered "Web content" back then (you think we're kidding).

        The long, cold days of the "Browser Wars." Netscape and Microsoft were duking it out for control of the world. After all, he who controls the browser controls the Universe, right?


        At the center of the fallout was the Web developer. During the wars, an arms race emerged as each browser company kept adding their own proprietary extensions in order to stay ahead. Who could keep up? And not only that, back in those days, you had to often write two separate Web pages: one for the Netscape browser and one for Internet Explorer. Not good.

        Ahhh... the end of the Browser Wars and, to our rescue, the World Wide Web Consortium (nickname: W3C). Their plan: to bring order to the Universe by creating the ONE HTML "standard" to rule them all.


        The key to their plan? Separate HTML's structure and presentation into two languages a language for structure (HTML 4.0) and a language for presentation (CSS) and convince the browser makers it was in their best interest to adopt these standards.


        But did their plan work?


        Uh, almost... with a few changes (see HTML 4.01).

        1989 1991

        1995

        1998



        Our goal in this chapter is to get ourselves up to HTML 4.01
        .


        Starting in Chapter 7, our goal is to be faithful to XHTML
        1.0. As always, the world keeps moving, so we'll also talk later in the book about where things are going.


        HTML 4.01

        XHTML 1.0

        ????

        Ah, the good life. HTML 4.01 entered the scene in 1999, and is the most current version of HTML. While everyone hoped 4.0 would be the ONE, it's always the case that a few fixes are needed here and there. No biggies and nothing to worry about.


        Compared to the early days of HTML (when we all had to walk barefoot in 6 feet of snow, uphill both ways), we were all cruising along writing HTML 4.01 and sleeping well at night knowing that almost all browsers (at least the ones anyone would care about) are going to display your content just fine.

        But, of course, just as we were all getting comfortable, new technologies were created and things changed. HTML and another markup language known as XML got together, and sooner than you can say "arranged marriage," XHTML 1.0 was born. XHTML inherited traits from both parents: popularity and browser-friendliness from HTML, and extensibility and strictness from XML. What does that mean? You'll find out soon enough, because we're going to have you creating XHTML Web pages before you can say "Extensible Hypertext Markup Language." Well, at least in the next chapter.

        And what will happen in the future? Will we all be going to work in flying cars and swallowing nutrition pills for dinner? Keep reading to find out.

        1999

        2000

         




        6.1.1. The Browser Exposed


        This week's interview: Why do you care which version of HTML you're displaying?


        Head First: We're glad to have you here, Browser. As you know, "HTML versions" have become a popular issue. What's the deal with that? You're a Web browser after all. I give you HTML and you display it the best you can.


        Browser: Being a browser is tough these days... there are a lot of Web pages out there and many are written with old versions of HTML or with mistakes in their markup. Like you said, my job is to try to display every single one of those pages, no matter what.


        Head First: So what's the big deal? What does it really matter which version of HTML I use?


        Browser: Remember the browser wars? All kinds of elements were added to HTML that we aren't supposed to use anymore. But some people expect us browsers to be able to display them anyway, and we don't always agree on how that should be done.


        Head First: Why aren't we supposed to use those elements any more?


        Browser: Well, before CSS was invented, HTML had elements that were there for presentation, not structure. Now, with CSS, we don't need those anymore, but there are still plenty of Web pages out there that use them.


        Head First: I think I'm starting to see the problem. So how do you manage to display all these pages in all these different versions of HTML? That's quite a tall order.


        Browser: Yeah, like I said, it's tough being a browser. What we end up doing is having two sets of rules for displaying Web pages: one for old HTML and one for the newer, standard HTML. When I use the old rules, I call that my "quirks mode
        " because there are so many weird things that can happen on those pages.


        Head First: That sounds like a pretty good solution to me...


        Browser: Well, it can get you into trouble, though. If you're writing new HTML, but you don't tell me you're writing new HTML, then I have to assume you're writing old HTML, and go into quirks mode just in case. And you don't want that.


        Head First: What do you mean?


        Browser: Not all browsers agree on how to display the older stuff, but we all do a pretty consistent job with standard HTML. So if you're using standard HTML, tell me and you'll get more consistent results in all browsers.


        Head First: Oh, so you can end up using the quirks mode rules on the pages written using new HTML?


        Browser: Exactly. If I don't know you're writing new HTML, I go into my quirks mode and do the best I can. But, you don't want that because all those "quirks" mean that your pages might end up looking a bit off, when they could have looked beautiful if I'd only known you were using new HTML.


        Head First: Ahh. So, what's the solution to this mess? We definitely want our Web pages to look good.


        Browser: Easy. Tell me up front which version of HTML you're using. That way I know which rules to use to display your page.


        Head First: Got it. Thank you, Browser!













        Study Methodology













        Study Methodology



        Journal Selection


        Many studies have ranked IS journals in terms of citations or other measures (Hardgrave & Walstrom, 1997; Mylonopoulos & Theoharakis, 2001; Whitman, Hendrickson, & Townsend, 1999). By using these studies as a guideline and limiting the current study to strictly research journals (e.g., Communications of the ACM would not qualify) and by further limiting the study to specifically IS journals (i.e., Decision Sciences and Management Science would not qualify), we selected three journals to use in our sample: MIS Quarterly, Information Systems Research, and Journal of Management Information Systems. These three final selections were the top-ranked IS research journals in each of the above-mentioned studies. Other researchers (e.g., Boudreau et al., 2001) have used similar guidelines when selecting journals from which to sample. We also selected a relatively large time period to determine if researcher habits had changed over time. Therefore, we examined all articles in the three selected journals for the years 1996–2000.





        Classification of Articles


        Each article was grouped according to article type, as shown in Table 1. To initially classify an article, one of the authors would read the article and classify accordingly. Then the other author would also read the article and classify accordingly. Any articles for which there existed a disagreement among researchers, later discussions were able to resolve it so that the researchers agreed on the classification of all articles. In studies using more than one methodology, the predominant methodology was used to classify each article—that is, a case study that used a survey as a small part of the analysis would be classified as a case study, not a survey.


























































        Table 1: Article Classification.


        Type of Study




        Journal (1996–2000)


        �


        Information Systems Research




        MIS Quarterly




        Journal of Management Information Systems




        TOTALS



        Survey/Questionnaire



        31[1]


        23.5% [2]



        31


        25.0%



        54


        31.40%



        116


        27.1%



        Theory/System Development [3]



        41


        31.1%



        29


        23.4%



        57


        33.1%



        127


        29.7%



        Case Study



        11


        8.3%



        29


        23.4%



        19


        11.1%



        59


        13.8%



        Experiment



        11


        8.3%



        5


        4.0%



        27


        15.7%



        43


        10.1%



        Mathematical Modeling [4]



        16


        12.1%



        4


        3.2%



        9


        5.2%



        29


        6.8%



        Qualitative Analysis



        3


        2.3%



        12


        9.7%



        2


        1.2%



        17


        4.0%



        Interviews



        1


        0.8%



        5


        4.0%



        2


        1.2%



        8


        1.9%



        Event Study/Objective Data



        4


        3.0%



        3


        2.4%



        0


        0.00%



        7


        1.6%



        Action Research



        0


        0.00%



        1


        0.8%



        1


        0.6%



        2


        0.5%



        Delphi Method



        0


        0.00%



        2


        1.6%



        0


        0.00%



        2


        0.5%



        Field Study



        13


        9.9%



        2


        1.6%



        1


        0.6%



        16


        3.7%



        Electronic Brainstorming



        1


        0.8%



        1


        0.8%



        0


        0.00%



        2


        0.5%



        TOTALS



        132


        100.0%



        124


        100.0%



        172


        100.0%



        428


        100.0%





        [1]Number of articles by journal;





        [2]Percent of total articles by journal;





        [3]Includes research note/analysis/response; also includes secondary data analysis;





        [4]Includes simulation, algorithms, economic modeling, etc.




        Of 428 total research articles published in the five-year period, 116 (27.1%) were classified as using a survey approach with self-reported data as the predominant method. Another 127 (29.7%) were classified as theory/system development, including research note/analysis/response, as well as secondary data analysis. No other category accounted for more than 13.8% (case study) of the articles. Clearly, with over one-fourth of the published research in the top journals categorized as using a survey methodology, this approach appears important to the IS community. Therefore, common method variance, a potential confounding factor in survey research, should be of interest to the IS community at large. The next section describes how IS researchers have handled common method variance over the time period specified.