Wednesday, November 25, 2009

Why Worry About Versioning?











 < Day Day Up > 







Why Worry About Versioning?



Having a good version scheme for your software is important for several reasons. The following are the top five things a version scheme allows you to do (in random order):



  • Track your product binaries to the original source files.

  • Re-create a past build by having meaningful labels in your source tree.

  • Avoid "DLL hell" �multiple versions of the same file (library in this case) on a machine.

  • Help your setup program handle upgrades and service packs.

  • Provide your product support and Q/A teams with an easy way to identify the bits they are working with.



So, how do you keep track of files in a product and link them back to the owner? How can you tell that you are testing or using the latest version of a released file? What about the rest of the reasons in the list? This chapter describes my recommendations for the most effective and easiest way to set up and apply versioning to your software. Many different schemes are available, and you should feel free to create your own versioning method.



Ultimately, like most of the other topics in this book, the responsibility to apply versioning to the files in a build tends to fall into the hands of the build team. That might be because it is usually the build team that has to deal with the headaches that come from having a poor versioning scheme. Therefore, it is in their best interest to publish, promote, and enforce a good versioning scheme. If the build team does not own this, then someone who does not understand the full implications of versioning will make the rules. Needless to say, this would not be desirable for anybody involved with the product.



What is the best way to accomplish this? Let's start with the version number and work our way down.















     < Day Day Up > 



    Other Patterns













    Other Patterns

    System performance is naturally in tension with the control of the system. There are clear examples of this in the way that many of the system performance patterns, such as LOAD-BALANCED ELEMENTS, DEDICATED WEB AND APPLICATION SERVERS and COMMON PERSISTENT STORE, gain much of their benefit by increasing the number of elements in the system which means that there are more elements to configure as part of a SYSTEM OVERVIEW and more information generated from CONTINUAL STATUS REPORTING (hence more network traffic). Similarly, the addition of security measures such as SECURE CHANNELS and INFORMATION OBSCURITY slow down the overall performance of those parts of the system to which they are applied. This is why you will usually apply a mixture of control and performance patterns, as the latter help to offset the negative impacts on performance of the former. The only clear place where a performance pattern reinforces a control pattern is the way that DEDICATED WEB AND APPLICATION SERVERS is pretty much a prerequisite for a DEMILITARIZED ZONE.


    There is also a natural tension between many system evolution patterns and performance patterns. The overheads introduced by a VIRTUAL PLATFORM or DYNAMICALLY DISCOVERABLE ELEMENTS will slow down the system, so it is common to apply system performance patterns to compensate for this. Conversely, there is some degree of reinforcement as EXPANDABLE HARDWARE and DYNAMICALLY-DISCOVERABLE ELEMENTS complement performance patterns, such as LOAD-BALANCED ELEMENTS, that help to improve the scalability of the system. Similarly, the application of SEPARATE SYSTEM-MANAGED DATA can help to reduce the amount of data that has to be kept synchronized by DATA REPLICATION.


    In the next chapter we will look at patterns that help to make the system more controllable.











    Achilles





    Achilles



    Achilles is one of the most unstable but
    remarkably powerful Web hacking tools available for Windows. It acts like a Web
    proxy, capturing information being sent back to the Web server and then
    allowing the user to manipulate that information and send it to the server. This
    ability to modify on the fly what the user's browser is sending to the Web
    server allows an attacker to attempt various nefarious attempts, including SQL
    injection and impersonation.



    Achilles contains the following features:



    style='font-size:10.0pt;font-family:Symbol'>�        
    Proxy server (port configurable)



    style='font-size:10.0pt;font-family:Symbol'>�        
    HTTP and SSL interception



    lang=EN-GB style='font-size:10.0pt;font-family:Symbol'>�        
    Insert/alter data in HTTP stream



    lang=EN-GB style='font-size:10.0pt;font-family:Symbol'>�        
    Recalculation of the required HTTP fields



    style='font-size:10.0pt;font-family:Symbol'>�        
    Buffer overflow testing



    lang=EN-GB style='font-size:10.0pt;font-family:Symbol'>�        
    Log of HTTP and SSL sessions



    The main features that we demonstrate here
    are HTTP and SSL interception and altering of data�by far the largest
    components of Achilles.
    style='color:#003399'>Figure 15-11 illustrates the process.



    style='font-size:10.5pt;font-family:Arial'>Figure 15-11. Achilles interception
    of data




    To use Achilles, we must start the application and then check
    these options:



    style='font-size:10.0pt;font-family:Symbol'>�        
    Intercept Mode ON



    style='font-size:10.0pt;font-family:Symbol'>�        
    Intercept Client Data



    Once we have selected them, we simply hit the Start button.
    But before we can use Achilles to proxy our connections through to the Internet
    and the Web site being tested, we must configure our Internet browser to use
    the Achilles proxy server. By default, the Achilles proxy runs on port 5000, so
    to enable our Internet Explorer browser to use this port for proxying, we
    follow these steps:



    1.      
    From the menu, select Tools->Internet Options.





    2.style='font:7.0pt "Times New Roman"'>       value=2>Select the Connections tab.





    3.style='font:7.0pt "Times New Roman"'>       value=3>Select the LAN Settings button.





    4.style='font:7.0pt "Times New Roman"'>       value=4>Check the Use a proxy server for your LAN� box, in the Proxy Server
    group.





    5.style='font:7.0pt "Times New Roman"'>       value=5>In the Address field, type in the localhost address: 127.0.0.1.





    6.style='font:7.0pt "Times New Roman"'>       value=6>In the Port field, type in the default Achilles port: 5000 (or whatever
    you setup Achilles for).





    Once we've set up the browser, we begin surfing the Web
    through Achilles and observe every request sent to the target server. For
    example, style='color:#003399'>Figure 15-12 illustrates how a GET request was
    made to the target and displays the header fields.



    style='font-size:10.5pt;font-family:Arial'>Figure 15-12. Achilles interception
    of a GET request




    We've sent a GET request to the target Web
    server, and Achilles has intercepted it. Now we must hit the Send button at the
    bottom left to send the request as it is in the window to the target Web
    server. If we wanted to modify the window in any way, we would simply change
    the information in it and then hit Send.



    In addition to client data interception,
    Achilles also offers the ability to capture server data. We just click in the
    Intercept Server Data(text) checkbox and make a request of the server. Not only
    does the client's request get intercepted, but so too does the server's reply. The
    server's response isn't critical to Web assessment, but it can be helpful in
    understanding the cookies being set and general state management attempts made
    by the Web server.



    Unfortunately, Achilles can't tell us which
    part of the request or response we're viewing in the edit box. In other words,
    what we see in the edit box may be a request sent from our browser to the Web
    server or a response from the Web server to our browser. An understanding of
    this sequence (as detailed in
    lang=EN-GB style='color:#003399'>Chapter 4) is
    essential to effective Achilles use.



    An example of Achilles in action is presented
    next, in conjunction with Cookie Pal.
    For more information on
    impersonation, see style='color:#003399'>Chapter 13.



     





    Firewall Functions












    Firewall Functions

    As yet, no other portable library has seen libdnet's capability to interface with an operating system's native firewall functionality. Many modern robust operating systems contain support for some sort of firewall capabilities. While similar in theory, all seem to differ wildly in implementation. Libdnet bridges the gap and enables the application programmer to access this functionality in a portable and consistent fashion. At this writing, the following operating systems are supported: OpenBSD, FreeBSD, NetBSD, Linux, and MacOS with Solaris functionality in the works.


    You should employ the fw_pack_rule() macro to populate struct fw_rule (described in the datatypes section).




    fw_t *fw_open(void);



    fw_open() opens and initializes a firewall handle for use in subsequent firewall functions. Upon success, the function returns a valid fw_t descriptor; upon failure, the function returns NULL.






    Note 

    In most cases, a firewall handle contains a file descriptor with which the internal libdnet code sets socket options or performs ioctl() s.





    int fw_add(fw_t *f, struct fw_rule *rule);



    fw_add() adds the firewall rule rule to the firewall subsystem that f references. Upon success, the function returns 0; upon failure, the function returns −1.




    int fw_delete(fw_t *f, struct fw_rule *rule);



    fw_delete() deletes the firewall rule rule from the firewall subsystem that f references. Upon success, the function returns 0; upon failure, the function returns −1.




    int fw_loop(fw_t *f, fw_handler callback, void *arg);
    int callback(const struct fw_rule *rule, void *arg);



    returns −1 and sets errno. The fw_loop() callback function format expects two arguments: a pointer to the firewall rule and the optional argument arg.




    fw_t *fw_close(fw_t *f);



    fw_close() closes the firewall interface that f references. The function returns NULL.





    fw_pack_rule(rule, dev, o, dir, p, s, d, sp1, sp2, dp1, dp2);




    fw_pack_rule() is a macro that fills in a firewall rule structure rule elements with the arguments specified corresponding to each member, as Table 6.4 summarizes.

























































































    Table 6.4: fw_pack_rule() Arguments

    ARGUMENT



    MEANING







    rule



    the libdnet firewall rule structure to be populated







    dev



    the canonical name of the device, up to 14 bytes including NULL terminator







    o



    firewall operation type







    dir



    direction the rule should be applied







    p



    protocol







    s



    source address







    d



    destination address







    sp1



    either the low source port number or the ICMP type







    sp2



    either the high source port number or the ICMP mask







    dp1



    either the low destination port number or the ICMP code







    dp2



    either the high destination port number or the ICMP mask





















    LOAD REVIEW









































    Prev don't be afraid of buying books Next






























    LOAD REVIEW






    Add support to
    persistence for loading reviews.





    Similarly to the previous task, we only need to
    concern ourselves with reading a MovieList that contains a
    review.






    Test 102.
    Reading an XML stream that contains text for a rating element
    results in that rating having an attached review.












    We need to add a test to
    TestMovieListReading. Just for fun, we'll take a slightly
    different approach this time. The existing test for reading a movie
    uses a fixture that uses a movie with two ratings. Let's add a
    review to one of them.





    Test 102: Reading an XML stream that
    contains text for a rating element results in that rating having an
    attached review



    First, a tweak to setUp():




    oneMoviePrefix = "<movielist>" +
    "<movie name=\"Star Wars\" " +
    "category=\"Science Fiction\">" +
    "<ratings>" +
    "<rating value=\"3\" " +
    "source=\"Dave\" />" +
    "<rating value=\"5\" " +
    "source=\"Jason\">" +
    "Great movie!" +
    "</rating>" +
    "</ratings>" +
    "</movie>";






    This needs a corresponding tweak to the
    test:




    public void testReadingOneMovie() throws Exception {
    //...
    Rating firstRating =(Rating)ratingIterator.next();

    //...
    assertFalse("First rating should not have a review.",
    firstRating.hasReview());
    //...
    Rating secondRating =(Rating)ratingIterator.next();

    //...
    assertTrue("Second rating should have a review.",
    secondRating.hasReview());

    assertEquals("Second rating's review is wrong.",
    "Great movie!",
    secondRating.getReview());
    //...
    }






    As expected, this test fails on the assertion
    that the second rating has a review. To correct that, we need to
    revisit processRating() in
    XMLMovieListReader:




    private Rating processRating(Element ratingElement) throws IOException {
    //...
    String review = ratingElement.getTextTrim();
    return new Rating(value, source, review);
    }







    Green.















































    Amazon






    Volume II ECS Software Architecture Views











    Team-Fly

     

     

















    Documenting Software Architectures: Views and Beyond
    By
    Paul Clements, Felix Bachmann, Len Bass, David Garlan, James Ivers, Reed Little, Robert Nord, Judith Stafford
    Table of Contents
    Appendix A. 
    Excerpts from a Software Architecture Documentation Package







    Volume II ECS Software Architecture Views


    CONTENTS


    Chapter 1 Module Decomposition View



    1.1. Module Decomposition View Packet 1: The ECS System


    1.2. Module Decomposition View Packet 2: The Science Data Processing Segment


    1.3. Module Decomposition View Packet 3: The Client Subsystem


    1.4. Module Decomposition View Packet 4: The Interoperability Subsystem


    1.5. Module Decomposition View Packet 5: The Ingest Subsystem


    1.6. Module Decomposition View Packet 6: The Data Management Subsystem


    1.7. Module Decomposition View Packet 7: The Data Processing Subsystem


    1.8. Module Decomposition View Packet 8: The Data Server Subsystem


    1.9. Module Decomposition View Packet 9: The Planning Subsystem


    1.10. Module Decomposition View Packet 10: The Communications and System Management Segment (CSMS)


    1.11. Module Decomposition View Packet 11: The System Management Subsystem


    1.12. Module Decomposition View Packet 12: The Communications Subsystem


    1.13. Module Decomposition View Packet 13: The Internetworking Subsystem


    1.14. Module Decomposition View Packet 14: Flight Operations Segment (FOS)



    Chapter 2 Module Uses View



    2.1. Module Uses View Packet 1: The Science Data Processing Segment (SDPS)


    2.2. Module Uses View Packet 2: The Communications and System Management Segment (CSMS)


    2.3. Module Uses View Packet 3: The Flight Operations Segment (FOS)



    Chapter 3 Module Generalization View



    3.1. Module Generalization View Packet 1: The Science Data Processing Segment (SDPS)



    Chapter 4 Module Layered View



    4.1. Module Layered View Packet 1: The ECS System



    Chapter 5 C&C Pipe-and-Filter View



    5.1. C&C Pipe-and-Filter View Packet 1: The ECS System



    Chapter 6 C&C Shared-Data View



    6.1. C&C Shared-Data View Packet 1: The Data Management Subsystem



    Chapter 7 C&C Communicating-Processes View



    7.1. C&C Communicating-Processes View Packet 1: Ingest Subsystem


    7.2. C&C Communicating-Processes View Packet 2: Data Server Subsystem


    7.3. C&C Communicating-Processes View Packet 3: Data Management Subsystem


    7.4. C&C Communicating-Processes View Packet 4: Client Subsystem


    7.5. C&C Communicating-Processes View Packet 5: Interoperability Subsystem


    7.6. C&C Communicating-Processes View Packet 6: Planning Subsystem


    7.7. C&C Communicating-Processes View Packet 7: Data Processing Subsystem


    7.8. C&C Communicating-Processes View Packet 8: Communications Subsystem


    7.9. C&C Communicating-Processes View Packet 9: System Management Subsystem


    7.10. C&C Communicating-Processes View Packet 10: Internetworking Subsystem



    Chapter 8 Allocation Deployment View



    8.1. Allocation Deployment View Packet 1: The ECS System



    Chapter 9 Allocation Implementation View



    9.1. Allocation Implementation View Packet 1: The ECS System



    Chapter 10 Allocation Work Assignment View



    10.1. Allocation Work Assignment View Packet 1: The ECS System













      Team-Fly

       

       





      Top



      Chapter 8: Finite State Verification












      Chapter 8: Finite State Verification



      Finite state verification techniques are intermediate in power and cost between construction of simple control and data flow models, on the one hand, and reasoning with the full strength of symbolic execution and theorem proving on the other. They automatically explore finite but potentially very large representations of program behavior to address important properties. They are particularly useful for checking properties for which testing is inadequate. For example, synchronization faults in multi-threaded programs may trigger failures very rarely, or under conditions that are nearly impossible to re-create in testing, but finite state verification techniques can detect them by exhaustively considering all possible interleavings of concurrent processes. Finite state verification can similarly be used to systematically explore possible instantiations of a data model.




      8.1 Overview


      Most important properties of program execution are undecidable in general, but finite state verification can automatically prove some significant properties of a finite model of the infinite execution space. Of course, there is no magic: We must carefully reconcile and balance trade-offs among the generality of the properties to be checked, the class of programs or models that can be checked, computational effort, and human effort to use the techniques.


      Symbolic execution and formal reasoning can prove many properties of program behavior, but the power to prove complex properties is obtained at the cost of devising complex conditions and invariants and expending potentially unbounded computational effort. Construction of control and data flow models, on the other hand, can be fully and efficiently automated, but is typically limited to very simple program properties. Finite state verification borrows techniques from symbolic execution and formal verification, but like control and data flow analysis, applies them to models that abstract the potentially infinite state space of program behavior into finite representations. Finite state verification techniques fall between basic flow analyses and full-blown formal verification in the richness of properties they can address and in the human guidance and computational effort they require.



      Since even simple properties of programs are undecidable in general, one cannot expect an algorithmic technique to provide precise answers in all cases. Often finite state verification is used to augment or substitute for testing when the optimistic inaccuracy of testing (due to examining only a sample of the program state space) is unacceptable. Techniques are therefore often designed to provide results that are tantamount to formal proofs of program properties. In trade for this assurance, both the programs and properties that can be checked are severely restricted. Restrictions on program constructs typically appear in procedures for deriving a finite state model from a program, generating program code from a design model, or verifying consistency between a program and a separately constructed model.


      Finite state verification techniques include algorithmic checks, but it is misleading to characterize them as completely automated. Human effort and considerable skill are usually required to prepare a finite state model and a suitable specification for the automated analysis step. Very often there is an iterative process in which the first several attempts at verification produce reports of impossible or unimportant faults, which are addressed by repeatedly refining the specification or the model.


      The automated step can be computationally costly, and the computational cost can impact the cost of preparing the model and specification. A considerable amount of manual effort may be expended just in obtaining a model that can be analyzed within available time and memory, and tuning a model or specification to avoid combinatorial explosion is itself a demanding task. The manual task of refining a model and specification to obtain either assurance or useful reports of real faults in design or coding is much less expensive if the analysis step is near-interactive than if it requires several minutes or hours.


      Some analysis techniques perform quite tolerably on small models, but their computational demands grow very rapidly with model size. These may be perfectly acceptable for a simple model of a critical component, such as a protocol whose description does not depend on the size of the system in which it is implemented. In other cases, scalability of the finite state verification technique is likely to be a limiting factor in its useful application.


      Finite state verification techniques vary widely in the balance they strike on issues of generality, precision, automation, computational effort, and scalability. A core idea shared by all is that a question about a program is translated into a simpler question about a finite state model of the program, as illustrated in Figure 8.1. Ultimately, one question about the program (Does it conform to the property we want to check?) is divided into two (Does the model conform to the simpler property we can check? Is it an accurate model of the program?)






      Figure 8.1: The finite state verification framework.

      The model may be derived from an actual program, like the control flow and data flow models described in prior chapters, or from some other design artifact (e.g., a program specification). Restrictions on the program may be required to derive a model automatically from a program. It is also possible to derive program code from annotated models.[1] If either the model or the program is derived automatically from the other, we may be able to do so in a way that guarantees consistency between the two.



      We may also be able to check consistency automatically even if the derivation is not automatic. Alternatively, the accuracy of the model may be assessed by conformance testing, treating the model as a kind of specification. The combination of finite state verification and conformance testing is often more effective than directly testing for the property of interest, because a discrepancy that is easily discovered in conformance testing may very rarely lead to a run-time violation of the property (e.g., it is much easier to detect that a particular lock is not held during access to a shared data structure than to catch the occasional data race that the lock protects against).


      A property to be checked can be implicit in a finite state verification tool (e.g., a tool specialized just for detecting potential null pointer references), or it may be expressed in a specification formalism that is purposely limited to a class of properties that can be effectively verified using a particular checking technique. Often the real property of interest is not amenable to efficient automated checking, but a simpler and more restrictive property is. That is, the property checked by a finite state verification tool may be sufficient but not necessary for the property of interest. For example, verifying freedom from race conditions on a shared data structure is much more difficult than verifying that some lock is always held by threads accessing that structure; the latter is a sufficient but not necessary condition for the former. This means that we may exclude correct software that we are not able to verify, but we can be sure that the accepted software satisfies the property of interest.






      [1]Note that one may independently derive several different models from one program, but deriving one program from several different models is much more difficult.