<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Hitchhiker’s Guide to Test Automation</title>
	<atom:link href="http://www.testing-software.org/feed" rel="self" type="application/rss+xml" />
	<link>http://www.testing-software.org</link>
	<description>Software Quality Assurance and Test Automation in Practice</description>
	<lastBuildDate>Sat, 29 Oct 2011 21:55:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>PyCon DE talk on &#8220;FOSS Ajax Performance Test Harness&#8221; was recorded</title>
		<link>http://www.testing-software.org/tools/ajax-performance-test-harness.html</link>
		<comments>http://www.testing-software.org/tools/ajax-performance-test-harness.html#comments</comments>
		<pubDate>Sat, 29 Oct 2011 21:50:29 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.testing-software.org/?p=162</guid>
		<description><![CDATA[The Pycon DE 2011 team did an awesome job in recording all the conference talks. The quality is extraordinary. Note: Narrative is in German. Slides: Mark_Fink_Ajax_PerfTest_Harness_v1.0 &#160;]]></description>
			<content:encoded><![CDATA[<p>The Pycon DE 2011 team did an awesome job in recording all the conference talks. The quality is extraordinary.</p>
<p>Note: Narrative is in German.</p>
<p><iframe src="http://blip.tv/play/AYLYlGUC.html" width="550" height="470" frameborder="0" allowfullscreen></iframe><embed type="application/x-shockwave-flash" src="http://a.blip.tv/api.swf#AYLYlGUC" style="display:none"></embed><br />
Slides:</p>
<p><a href="http://www.testing-software.org/wp-content/uploads/2011/10/Mark_Fink_Ajax_PerfTest_Harness_v1.0.pdf">Mark_Fink_Ajax_PerfTest_Harness_v1.0</a></p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/tools/ajax-performance-test-harness.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ajaxrunner</title>
		<link>http://www.testing-software.org/webapp-testing/ajaxrunner.html</link>
		<comments>http://www.testing-software.org/webapp-testing/ajaxrunner.html#comments</comments>
		<pubDate>Mon, 19 Sep 2011 19:58:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Webapp-Testing]]></category>
		<category><![CDATA[ajaxrunner]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.testing-software.org/?p=123</guid>
		<description><![CDATA[Pycon UK 2011 is comming up this weekend. I will give a talk on &#8220;Open source tool harness for perfomance testing AJAX applications&#8221;. I will explain how I think existing open source test tools can be used to performance test your AJAX applications. I have been working on some clue code which I call Ajaxrunner. [...]]]></description>
			<content:encoded><![CDATA[<p>Pycon UK 2011 is comming up this weekend. I will give a talk on &#8220;Open source tool harness for perfomance testing AJAX applications&#8221;. I will explain how I think existing open source test tools can be used to performance test your AJAX applications. I have been working on some clue code which I call Ajaxrunner. I would love to get some feedback from you.</p>
<p>Three components of Ajaxrunner:</p>
<ul>
<li>Analyze (extract information from existing data and make it available)</li>
<li>Record &amp; Script (to prepare testcases)</li>
<li>Runtime environment and Admin to execute your performance tests</li>
</ul>
<p>I will demo all three parts during the talk. Video on Record &amp; Script with Selenium-IDE:</p>
<p><object width="500" height="281"><param name="movie" value="http://www.youtube.com/v/hhbr5e06Kbg?version=3"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/hhbr5e06Kbg?version=3" type="application/x-shockwave-flash" width="500" height="281" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>This is the first time I talk publicly about Ajaxrunner. I will continue to work towards its first release over the next weeks.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/webapp-testing/ajaxrunner.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Functional Test Automation with Selenium</title>
		<link>http://www.testing-software.org/webapp-testing/webapp_testing_dsl.html</link>
		<comments>http://www.testing-software.org/webapp-testing/webapp_testing_dsl.html#comments</comments>
		<pubDate>Sat, 16 Jul 2011 14:09:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Webapp-Testing]]></category>
		<category><![CDATA[selenium]]></category>

		<guid isPermaLink="false">http://book.mark-fink.de/?p=105</guid>
		<description><![CDATA[Currently functional test automation is rarely applied to its full potential, therefore often delivering poor and inadequate results. Consequently functional test automation is often abandoned. Test automation can play an important role in software development, significantly improving quality and allowing shorter development cycles and time to market. I propose an approach for efficiently automating functional [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div id="functional-test-automation-with-selenium" class="section">
<h1><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">Currently functional test automation is rarely applied to its full potential, therefore often delivering poor and inadequate results. Consequently functional test automation is often abandoned.</span></h1>
<div class="admonition-abstract admonition ">
<p class="last">Test automation can play an important role in software development, significantly improving quality and allowing shorter development cycles and time to market. I propose an approach for efficiently automating functional tests with DSLs that are readable for domain experts (requirement owners) and encourage re-use. This leads to better software quality thanks to the knowledge input from the domain experts into the test suite. Re-usable building blocks lead to lower maintenance efforts for the test suite.</p>
</div>
<div id="introduction" class="section">
<h2>Introduction</h2>
<p>Testing is essential to software quality. The success of service oriented companies heavily depends on the quality of their software. It is still not clear in what way to apply functional test automation in order to significantly improve software quality.</p>
<p>Here I will describe an approach for how to successfully implement functional test automation which in comparison to the traditional approach significantly reduces the cost of ownership of a test suite. The approach mitigates the risk of fast evolving software through the use of maintainable functional test automation.</p>
<p>This paper will identify and describe the problems of functional test automation and propose an approach for how to address the problems.</p>
<p>My contributions:</p>
<ul class="simple">
<li>My approach significantly reduces the total cost of ownership of an automated functional test suite.</li>
<li>I have been experiencing in practice that domain experts are not involved in testing and, what is worse, domain specific tests are neither documented nor executed. I show how this approach involves the domain experts in the functional test automation.</li>
<li>I analysed existing approaches that could support DSL Modelling. I show how to use the existing knowledge and leverage it in order to successfully jump-start a test automation initiative.</li>
<li>I demonstrate how to implement this approach in Python.</li>
<li>I use an up-to-date example throughout the whole paper to show the utilization of the various aspects of my approach.</li>
</ul>
</div>
<div id="the-problem" class="section">
<h2>The Problem</h2>
<p>Software experts agree that testing is essential to software quality. As with software engineering, strategies vary on how to do it. When arguing about the right testing strategy the discussion circles around the following contexts:</p>
<ul class="simple">
<li>What level of application testing is appropriate? Should we focus on unit testing, functional testing, GUI testing, integration testing?</li>
<li>How do we determine if the testing is finished? How do we decide if the product can be shipped/ released?</li>
<li>How often do we test? Every release, every month, every week, every day, or even after each change to the source code?</li>
<li>What tools do we use?</li>
<li>What methodologies should we follow?</li>
<li>What amount of tests should we automate?</li>
<li>Who performs the testing? Who owns the testing discipline or process?</li>
</ul>
<p>Test automation does not solve or even address all of the questions above but it should definitely be considered in your testing strategy. The biggest benefit of automated testing is that once the tests are implemented you can run them as often as your hardware allows at no additional cost. Also, automated tests are reproducible whereas manual tests, in many cases, are not. On the other hand, test automation itself is another expensive software development project. An automated test suite must be maintained to be effective, which is expensive, as well. For example GUI level test automation is typically created with the capture and replay method. If the GUI changes substantially the test cases need to be re-recorded. In an environment that evolves rapidly this can be hard to achieve. As an analogy to software-refactoring, in software development the test suite should be refactored to encourage reuse and the DRY (Don’t Repeat Yourself) pattern.</p>
<p>The following diagram shows the information flows in a typical software development process for service oriented industries such as telecommunications.</p>
<p><img style="width: 800px;" src="/wp-content/uploads/_images/software_development_process2.png" alt="Information Flow within the Software Development Process" /></p>
<p>The diagram gives an overview of the information flows between the business units within a company. The technical business units provide services like software development, end-to-end-testing and systems operation. The business department understands the markets in which the company operates and defines product strategies. The people in the business department define the requirements for software development and are the domain experts. They work closely with analysts from the technical development unit who capture and analyse the requirements. Experienced analysts can also be seen as domain experts. Domain experts frequently do not define domain specific requirements because, by nature, these seem trivial or too intuitive to specify. An example for such implicit domain knowledge is what products are placed in what channels. Instead they focus entirely on specifying requirements for the computer system. The problem I want to point to is that testers may lack domain specific knowledge, which in turn impacts the test results. As a rule, testers do not get in touch with domain experts because they work for different business units within the company. The test analysts and testers base their test case documentation on analysis and development artefacts such as requirements, analysis and specifications. If requirements have been based on computer system requirements, as opposed to requirements based on domain knowledge, then these artefacts will not contain domain specific knowledge. This means domain specific tests are not performed. As a consequence this can only mean that you must involve the domain experts in test initiatives. Leaving the cultural issues out of the equation for a moment, this is still difficult because domain experts are often lacking application knowledge, test knowledge and technical background. To be successful in domain specific testing you must involve the domain experts and bridge the technological gap in order to capture the domain specific knowledge you need for the test cases.</p>
<p>Automated testing has a lot of potential and is very promising but currently is not delivering all possible results because it makes the maintenance and domain specific knowledge questions more difficult to answer.</p>
<p>If properly done an automated functional test suite can:</p>
<ul class="simple">
<li>Reduce cost and time of regression testing.</li>
<li>Increase quality by freeing testers to focus on value added activities such as exploratory testing.</li>
<li>Increase quality by faster feedback to developers.</li>
<li>Capture and implement domain specific tests.</li>
<li>Make requirements explicit by giving developers executable acceptance tests.</li>
</ul>
</div>
<div id="domain-specific-languages-dsl-to-the-rescue" class="section">
<h2>Domain Specific Languages (DSL) to the rescue</h2>
<p>A <em>Domain Specific Language</em> (DSL), as opposed to a General Purpose Language (GPL), is a programming language tailored specifically to an application domain; rather than being for general purpose, it captures precisely the domain’s semantics. Popular examples for DSLs are HTML (used for document markup) and VHDL (used to describe electronic circuits). DSLs allow the concise description of an applications logic reducing the semantic distance between the problem and the program.</p>
<p>Testing tools and frameworks address a broad range of application domains (broad focus). This is natural because the tool vendor or developer wants to see his tool applied in a broad range of applications. For instance the Selenium test automation tool can be used to test a web shop application and the same tool can be used to test a social community web application. The tester or test automation developer is at the other extreme; he has a very narrow functional focus on the complexity of his application. He needs tooling that fits as well as possible in order to be able to succeed with the initiative and gain efficiency. He will probably start a new framework to exactly address his requirements. That is one of the reasons why there are so many frameworks available.</p>
<p>Besides writing a new framework there is another possibility to address the needs of the test automation developer. You can customize an existing framework so that it fits your needs. This can be done in two ways. The first and obvious way is to modify or extend the existing tool. Unfortunately this has its own problems, like the fact that the source code is not available for proprietary tools. Therefore updates, to new tool versions are problematic especially for customized proprietary solutions. The other alternative is to perform the customization within a layer on top of the existing tool. In this case you can totally shield away the complexity of the underlying testing tool. In the extreme, you can later if necessary exchange the underlying framework or tool you are using, without changing your test cases. In this variant the possibilities to extend functionality are limited. The positive aspects of the layering approach outweigh the negative therefore we will use this approach for this paper. The following diagram shows the different software layers within our testing approach.</p>
<p><img style="width: 400px;" src="/wp-content/uploads/_images/dsl_layers2.png" alt="Layers of the Test Automation Implementation" /></p>
<p>DSLs are by definition special purpose languages:</p>
<ul class="simple">
<li>Concrete expressions of domain knowledge (captured in human readable form, not buried into system source code).</li>
<li>Direct involvement of the domain experts. The DSL format can often be designed in a way that matches the format typically used by domain experts. This results in keeping experts in a very tight software life cycle loop.</li>
</ul>
<p>As explained in the last section, domain experts are often lacking technical background, but it is necessary to involve them in order to get domain specific testing right. The DSL you and I are going to build has its focus on the application domain and hides the complexity of the testing framework away. Since no testing framework knowledge is necessary this brings test automation in reach of application domain experts. With a little help they will be able to review and comment on test cases and draft outlines of new test cases soon. The goal of a functional testing DSL is to be as human readable as possible and to abstract the complexity of the underlying testing tools. The following example test case for the openstreetmap should give you an intuitive idea of what we want to achieve.</p>
<div class="highlight-python">
<pre>browse http://www.openstreetmap.org

search Von-Gumppenberg-Strasse, Schmiechen

pan right

zoom in</pre>
</div>
<p>Another test automation problem we want to address with the functional testing DSL is the expensive maintenance of the test suites. The DSL commands enforce reuse and reduce code duplication. The decomposition of the test cases into commands makes it easier to identify where to apply changes and simplify the changes as well. The DSL will enable maintenance of the test suite without the necessity of re-recording test cases after each change. This will significantly reduce maintenance costs and the cost of ownership of the automated test suite.</p>
</div>
<div id="dsl-modelling" class="section">
<h2>DSL Modelling</h2>
<p>The term DSL modelling is rarely used in literature. Most of the scientific papers on DSL use the terms DSL design and development. Most authors focus on the topic of implementing a DSL. They discuss differences, pros and cons of internal and external DSLs and describe implementation related patterns in great detail. Unfortunately the practice oriented reader who wants to use a DSL to solve a concrete problem is left alone when it comes to DSL modelling. In order to address the tasks necessary to model a specific application domain I will use the term DSL Modelling to distinguish it from the tasks necessary to implement a DSL, which I will address as DSL Implementation (the next section).</p>
<p>DSL modelling consists of the analysis of the problem domain, refinement and design, and the methods used to drive this process. A prerequisite for the design of a DSL is a detailed analysis and structuring of the application domain. Graphical <em>Feature Diagrams</em> [3] are part of the FODA methodology and have been proposed to organize the dependencies between such features, and to document variabilities. <strong>In DSL modelling it is important to capture variabilities of your application domain because variability is the key factor in identifying complexity in your application domain.</strong> The following diagram shows such a feature diagram for the application domain of our example.</p>
<p><img style="width: 800px;" src="/wp-content/uploads/_images/osm_feature_diagram2.png" alt="Feature Diagram for our Web Application Test example" /></p>
<p>The feature diagram helps us to document and drive the DSL modelling. Potential sources of features are:</p>
<ul class="simple">
<li>Existing and potential stakeholders.</li>
<li>Domain experts and domain literature.</li>
<li>Existing systems and Documentation.</li>
<li>Existing analysis and design models (Use-case models, Object-models, etc.).</li>
<li>Models created during development (Entity-Relationship-Model, Class-Diagram, etc.).</li>
</ul>
<p>For DSL modelling in the area of test automation we should use the following additional sources to look for features and vocabulary of domain specific knowledge:</p>
<ul class="simple">
<li>Product descriptions targeted to the customer.</li>
<li>Any other sources that describe the behaviour of the system in the terms used by the domain expert (change requests, trouble tickets, bug reports).</li>
<li>Descriptions of manual test cases of the area to be automated.</li>
</ul>
<p>Strategies to identify features from the Czarnecki book [1]:</p>
<ul class="simple">
<li>Look for important domain terminology that implies variability, for example, checking account vs. savings account.</li>
<li>Examine domain concepts for different sources of variability, for example, different stakeholders, client programs, settings, contexts, environments, aspects, and so on. In other words, investigate what different sets of requirements mean for different domain aspects.</li>
<li>Use feature starter sets to start the analysis. A feature starter set consists of a set of aspects for modelling. Some combinations of aspects are more appropriate for a given domain than for another. For example, authentication, security, transactions, logging, etc.</li>
<li>Look for features at any point in the development. As mentioned before, we have high-level system requirement features, architectural features, subsystem and component features, and implementation features. Thus, we have to maintain and update feature models during the entire development cycle. We may identify all kinds of features by investigating variability in use case, analysis, design and implementation models.</li>
<li>Identify more features than you initially intend to implement. This is a useful strategy which allows us to create room for growth.</li>
</ul>
<p>Steps in feature modelling from the Czarnecki book [1]:</p>
<ol class="arabic simple">
<li>Record similarities between instances, that is, common features, for example, all accounts have an account number.</li>
<li>Record differences between instances, that is, variability, for example, some accounts are checking accounts and others are savings accounts</li>
<li>Organize features in feature diagrams. Organize them into hierarchies and classify them as mandatory, alternative, optional.</li>
<li>Analyse feature combinations and interactions. We may find certain combinations to be invalid.</li>
<li>Record all the additional information regarding features such as short semantic descriptions, rationales for each feature, stakeholders and client programs interested in each feature, examples of systems with a given feature. Document constraints, default dependency rules, availability sites, binding sites, binding modes, open/closed attributes, and priorities.</li>
</ol>
<p>Start with steps 1 and 2 in the form of a brainstorming session by writing down as many features as you can. Then try to cluster them and organize them into feature hierarchies while identifying the kinds of variability involved (i.e. alternative, optional etc.). Finally, refine the feature diagrams by checking different combinations of the variable features, adding new features, and writing down additional constraints. Maintain and update the initial feature models during the rest of the development cycle. You may also start new diagrams at any point during the development.</p>
<p>The feature diagram is very helpful during domain analysis. The DSL modelling for our openstreetmap example is not yet finished. In general it is unclear how to proceed once a feature diagram exists [3]. I think in software engineering there is no “formula” which can be generically applied on how to implement a piece of software from a design model. Like in software engineering there are engineering skills necessary to transfer a feature diagram into a DSL. One thing that definitely helps to bridge this gap is the decision on how to implement the DSL in the first place. How to implement a DSL in Python is covered in the next section.</p>
</div>
<div id="dsl-implementation-in-python" class="section">
<h2>DSL Implementation in Python</h2>
<p>Two common variants exist for DSL implementation. A DSL can be implemented as internal DSL or external DSL. The terms internal DSL and external DSL have been coined by Martin Fowler [8]. An external DSL is a “independent” programming language. The <em>external DSL</em> is implemented like a general purpose programming language. Some kind of parser tool or framework is used to interpret or compile the external DSL based on a grammar to the target platform.</p>
<p>On the other hand, a DSL can be implemented as an <em>internal DSL</em>. This is also known as the piggyback pattern. The internal DSL is written like a normal program in the target programming language. The syntactic features of the target language are used to make the program more human readable. The programmer uses indentation and naming of the methods and variables to make the program read like sentences in a natural language. All the existing infrastructure of the target language like a parser, interpreter or compiler are used. It is also possible to extend or limit the features of the target language if necessary. The effort to create an internal DSL is usually smaller compared to creating an external DSL. Sometimes it also comes in handy to have the underlying power of the target language at hand. On the other hand the syntax of the internal DSL is limited by the syntax of the target language.</p>
<p>Internal DSLs are often implemented by use of <em>Method Chaining</em>. With method chaining it is easy to implement a DSL even in system programming languages like C++ and Java. The following code fragment shows the implementation of a test case as internal DSL in Python.</p>
<div class="highlight-python">
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">osm_dsl</span> <span class="kn">import</span> <span class="n">Browser</span>

<span class="n">Browser</span><span class="p">(</span><span class="s">"http://www.openstreetmap.org/"</span><span class="p">)</span> \
    <span class="o">.</span><span class="n">click_view</span><span class="p">()</span> \
    <span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s">"Von-Gumppenberg-Strasse, Schmiechen"</span><span class="p">)</span> \
    <span class="o">.</span><span class="n">pan_right</span><span class="p">()</span> \
    <span class="o">.</span><span class="n">zoom_in</span><span class="p">()</span></pre>
</div>
</div>
<p>Compared to natural English language this is strictly formatted and still has a lot of parentheses. Note that the verification steps for the automated test case will be built into the DSL commands and will not be visible in the test case description.</p>
<div class="highlight-python">
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">selenium</span>
<span class="kn">import</span> <span class="nn">unittest</span><span class="o">,</span> <span class="nn">time</span><span class="o">,</span> <span class="nn">re</span>

<span class="k">class</span> <span class="nc">Browser</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">website</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">setUp</span><span class="p">(</span><span class="n">website</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">zoom_in</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amount</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">amount</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"OpenLayers.Control </span><span class="se">\</span>
<span class="s"> .PanZoomBar_6_zoomin_innerImage"</span><span class="p">)</span>
            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">self</span>

    <span class="k">def</span> <span class="nf">pan_right</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amount</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">amount</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"OpenLayers.Control </span><span class="se">\</span>
<span class="s"> .PanZoomBar_6_panright_innerImage"</span><span class="p">)</span>
            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">self</span>
    <span class="o">...</span></pre>
</div>
</div>
<p>The above code sample shows the implementation of the commands “zoom_in” and “pan_right” for the internal DSL. In order to follow the method chaining pattern all methods in the example return a reference to the class instance.</p>
<p>The implementation of the functional testing DSL as an internal DSL is a valid option but in my opinion the resulting language is still not at all like natural language, and therefore not suitable for interaction with the domain experts. Alternatively the implementation as external DSL means additional effort for modelling and maintaining the grammar of the external DSL. It is clear that, when modelling a DSL for functional test automation, the language would change a couple of times in the beginning in order to adapt to the application domain, and to make it as human readable as possible. Changes to the DSL grammar would mean additional overhead when implementing an external DSL. I could not find a way to improve the readability of the internal DSL implementation in Python to an acceptable level. While looking for a way to improve the readability of the internal DSL, I had an idea for implementing an external DSL in such a way that the benefits of the internal DSL can be captured while having all the syntactic possibilities of an external DSL at hand. In fact the implementations of commands for the external DSL and internal DSL are almost identical in this approach. This means no additional effort for the implementation of the commands. The best thing is that during the start phase when you work with three or four commands, these can be modified without the need to change the grammar of the external DSL.</p>
<p>When automating test cases I always have a look at the manual test cases first. Manual test cases should be described in a way that a relatively inexperienced tester, who has read the application user guide, can execute the test case and verify the results. I think DSLs for test automation usually start small with about three to five implemented commands. These commands are used to formulate a couple of test cases. I have to adjust the commands a couple of times during this process until they perfectly fit my needs. The language grows step by step along the project. During maintenance of the test suite it will often be necessary to adjust the implementation of the commands due to changes in the GUI of the system under test.</p>
<p>The following sample shows a test case formulated in the external DSL. The test case is formulated in natural language which allows us to involve domain experts in the test automation project. The test case describes two different scenarios for location search. The first scenario is the search in the View tab which does not require the user to log in. The second scenario tests the location search in the Edit tab which requires a login.</p>
<div class="highlight-python">
<pre>Story Search Location uses osm_dsl

Scenario Search Location in View tab:
    browse http://www.openstreetmap.org
    search Von-Gumppenberg-Strasse, Schmiechen
    pan right
    zoom in

Scenario Search Location in Edit tab:
    browse http://www.openstreetmap.org
    click Edit
    login user mark identified by test1234
    search Von-Gumppenberg-Strasse, Schmiechen
    pan right
    zoom in
    logout</pre>
</div>
<p>Next we will take a look at the Selenium tools. For the recording of the raw tests I use the Selenium IDE. The Selenium IDE is a Firefox plugin used to record clicks on a webpage, to add wait conditions, and verification steps. We export a captured test case as a Python script. We can use this script later as a basis for the implementation of the DSL commands. We use another tool, the Selenium Server, for execution of the test cases. The Selenium Server provides the test profile for the web browser, starts and ends the web browser, and handles all the communication of our test suite with the web browser. I cover the usage of Selenium in more detail in an article “Functional testing of web applications with Selenium” on my website [5].</p>
<p>The following table shows a Selenium test case with all the technical details like wait conditions and verification steps.</p>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/osm_selenium_test2.png" alt="Selenium test case with all wait conditions" /></p>
<p>In Selenium IDE it is possible to export the recorded test case into a Python script which looks like the following:</p>
<div class="highlight-python">
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">selenium</span>
<span class="kn">import</span> <span class="nn">unittest</span><span class="o">,</span> <span class="nn">time</span><span class="o">,</span> <span class="nn">re</span>

<span class="k">class</span> <span class="nc">NewOsmTest</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span> <span class="o">=</span> <span class="n">selenium</span><span class="p">(</span><span class="s">"localhost"</span><span class="p">,</span> <span class="mi">4444</span><span class="p">,</span> <span class="s">"*chrome"</span><span class="p">,</span>
            <span class="s">"http://www.openstreetmap.org/"</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">test_new_osm_test_case</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">sel</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">type</span><span class="p">(</span><span class="s">"query"</span><span class="p">,</span> <span class="s">"Von-Gumppenberg-Strasse, Schmiechen"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"commit"</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"permalinkanchor"</span><span class="p">):</span> <span class="k">break</span>
            <span class="k">except</span><span class="p">:</span> <span class="k">pass</span>
            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s">"time out"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"OpenLayers.Control.PanZoomBar_6_panright_innerImage"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"OpenLayers.Control.PanZoomBar_6_zoomin_innerImage"</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"loginanchor"</span><span class="p">))</span>
        <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"loginanchor"</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"//form[@action='/login']"</span><span class="p">):</span>
                    <span class="k">break</span>
            <span class="k">except</span><span class="p">:</span> <span class="k">pass</span>
            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s">"time out"</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"loginanchor"</span><span class="p">))</span>
        <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
        <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"user_email"</span><span class="p">))</span>
        <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
        <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"user_password"</span><span class="p">))</span>
        <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">type</span><span class="p">(</span><span class="s">"user_email"</span><span class="p">,</span> <span class="s">"markfink"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">type</span><span class="p">(</span><span class="s">"user_password"</span><span class="p">,</span> <span class="s">"test1234"</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">failUnless</span><span class="p">(</span>
            <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"//form[@action='/login']"</span><span class="p">))</span>
        <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"commit"</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"link=markfink"</span><span class="p">):</span> <span class="k">break</span>
            <span class="k">except</span><span class="p">:</span> <span class="k">pass</span>
            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s">"time out"</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"link=markfink"</span><span class="p">))</span>
        <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"editanchor"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"logoutanchor"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">([],</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">unittest</span><span class="o">.</span><span class="n">main</span><span class="p">()</span></pre>
</div>
</div>
<p>It is relatively easy to identify which parts of the script implement certain aspects (search, zoom, login, &#8230;) of the test case. It also takes a little while to get used to reading the captured test cases. After a while you will slice the scripts into reusable commands in no time. Sometimes test cases that worked before, or which worked for another browser, will fail. This happens due to the asynchronous behavior of AJAX implementations. If this happens you must simply add another wait condition. It is better to add a waitForElement condition than a sleep() for a fixed time interval. Due to the fact that some browsers execute Javascript faster than others you must use waitFor conditions for synchronization to occur properly. After you slice the script into parts and form them into DSL commands, take some time to add additional verification steps. The DSL commands will be reused and you do not need to rework the verification steps of a command later if was done correctly the first time.</p>
<p>After some tweaking of the implementation of your external DSL commands would look something like that:</p>
<div class="highlight-python">
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">selenium</span>

<span class="nd">@dsl</span><span class="p">(</span><span class="s">'search (\w*)'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>
    <span class="n">sel</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>
    <span class="n">sel</span><span class="o">.</span><span class="n">type</span><span class="p">(</span><span class="s">"query"</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>
    <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"commit"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"permalinkanchor"</span><span class="p">):</span> <span class="k">break</span>
        <span class="k">except</span><span class="p">:</span> <span class="k">pass</span>
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span> <span class="n">fail</span><span class="p">(</span><span class="s">"time out"</span><span class="p">)</span>

<span class="nd">@dsl</span><span class="p">(</span><span class="s">'zoom in (\w*)'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">zoom_in</span><span class="p">(</span><span class="n">amount</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">amount</span><span class="p">):</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"OpenLayers.Control.PanZoomBar_6_zoomin_innerImage"</span><span class="p">)</span>

<span class="nd">@dsl</span><span class="p">(</span><span class="s">'pan right (\w*)'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">pan_right</span><span class="p">(</span><span class="n">amount</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">amount</span><span class="p">):</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"OpenLayers.Control.PanZoomBar_6_panright_innerImage"</span><span class="p">)</span>

<span class="nd">@dsl</span><span class="p">(</span><span class="s">'login user (\w+) identified by (\w+)'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="n">user_email</span><span class="p">,</span> <span class="n">user_password</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span> <span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"loginanchor"</span><span class="p">))</span>
    <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
    <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"loginanchor"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"//form[@action='/login']"</span><span class="p">):</span> <span class="k">break</span>
        <span class="k">except</span><span class="p">:</span> <span class="k">pass</span>
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span> <span class="n">fail</span><span class="p">(</span><span class="s">"time out"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span> <span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"loginanchor"</span><span class="p">))</span>
    <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
    <span class="k">try</span><span class="p">:</span> <span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"user_email"</span><span class="p">))</span>
    <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
    <span class="k">try</span><span class="p">:</span> <span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"user_password"</span><span class="p">))</span>
    <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
    <span class="n">sel</span><span class="o">.</span><span class="n">type</span><span class="p">(</span><span class="s">"user_email"</span><span class="p">,</span> <span class="n">user_email</span><span class="p">)</span>
    <span class="n">sel</span><span class="o">.</span><span class="n">type</span><span class="p">(</span><span class="s">"user_password"</span><span class="p">,</span> <span class="n">user_password</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span> <span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"//form[@action='/login']"</span><span class="p">))</span>
    <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
    <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"commit"</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"link="</span><span class="o">+</span><span class="n">user_email</span><span class="p">):</span> <span class="k">break</span>
        <span class="k">except</span><span class="p">:</span> <span class="k">pass</span>
        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span> <span class="n">fail</span><span class="p">(</span><span class="s">"time out"</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span> <span class="n">failUnless</span><span class="p">(</span><span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"link="</span><span class="o">+</span><span class="n">user_email</span><span class="p">))</span>
    <span class="k">except</span> <span class="ne">AssertionError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">verificationErrors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
<span class="o">...</span></pre>
</div>
</div>
<p>Note that the functions in the above source code block which form the DSL commands are modified by the @dsl decorator. The @dsl decorator links a regular expression statement to the function signature. This regular expression is used during execution of a test case scenario to identify which DSL command will be executed. The grammar an other infrastructure of the functional testing DSL is implemented as a Python nose unit test plugin (open source) [6].</p>
<p>I think this is really worth the effort. With a little bit of additional coding it is possible to break up the capture and replay tests into reusable DSL commands that can be easily reused to extend the test suite with more new test cases. The amount of work to fix timing issues and the time for writing additional verification steps pays back when you formulate new test cases based on these commands.</p>
<p>Now we have finished the implementation of our openstreetmap test case as an external DSL. The test case in this form is much more readable than the original Selenium test case (see the test case in the tabular form above). I would go so far as to say that domain experts, after a minimal amount of training, will be able to review test cases in this format. After a little practice, domain experts will probably be able to sketch new test cases that can than be automated incredibly quickly. Of course this depends heavily on the working environment. I would guess in a start-up-company environment domain experts would be motivated to support writing test cases in this way because of the high quality of the resulting software product.</p>
</div>
<div id="related-work" class="section">
<h2>Related Work</h2>
<p>Test automation could play an important role in software engineering. That is the reason why so much literature exists in this area which covers different approaches to the topic. In this section I want to compare the approach of the functional testing DSL with other approaches. I also give credit to other work that inspired me. I also want to give the reader reference points for further research.</p>
<p>Fit and Fitnesse [7] are very interesting testing tools that target similar goals like the functional testing DSL. The test cases are documented in tabular format. The tabular format helps to collect the domain knowledge of the test cases. The complexity of the underlying test implementations are hidden in so called fixtures. It is also possible to maintain Selenium tests with these tools. I personally think that Selenium has its strength in functional testing. For GUI or in-browser tests, I prefer the approach discussed in this article because I think that it is more flexible.</p>
<p>In the field I have seen implementations of functional test cases in XML. To implement test cases in XML is orthogonal to implementing them in an internal or external DSL. In fact, the implementation in XML is a DSL as well. I think that XML markup gets in the way when you want to collect and document domain specific knowledge from domain experts. During the XML hype many DSLs have been implemented in XML. A popular example where they used XML but should have used a DSL is ANT. ANT is a popular Java build framework. To build a complex application you often have the need for the power of a programming language. That is why so many additional tasks exist and are in use. The result is that ANT build files are overly complex and difficult to maintain.</p>
<p>Behaviour Driven Development (or BDD) is an agile software development technique that encourages collaboration between developers, QA and domain experts in a software project. It was originally conceived by Dan North [9]. BDD evolved from Test Driven Development. The focus of BDD is the language and interactions used in the process of software development. Developers who follow BDD use their native language in combination with the ubiquitous language of Domain Driven Design to describe the purpose and benefit of their code [4]. I was inspired by Dan North JBehave implementation when I designed the test scenarios for the functional testing DSL.</p>
<p>Another approach is Model Driven Testing. For Model Driven Testing you use the same Analysis and Design models that you use for the implementation and generate tests from them. As a prerequisite these models have to be standardized and complete, which is a problem for complex systems. While this looks promising, only time will tell if this approach is successful.</p>
<p>U2TP is the UML Testing Profile Specification of the Object Management Group [2]. This approach uses UML models to standardize the description of test concepts like black-box testing, local behaviour, distributed behaviour, test data. Again this looks promising but it is a brand new methodology. This means it will probably change radically in the near future and it will take some time to demonstrate whether this approach is successful in the industry.</p>
<p>Over that last 10 months I used much of my spare times to do research in the area of Domain Analysis and Domain Engineering. Domain Specific Languages, or Little Languages, have been a popular topic for Computer Scientists and Software Engineers since the 1970s. I was drawn by the idea that there must be a wealth of different methods and tools available to support DSL modelling. So far I have identified the Feature Diagrams I used in the DSL Modelling section above. Feature Diagrams are the main part of the FODA (Feature-Oriented Domain Analysis) method. Domain Engineering aims to collect, organize and store information about past software developments, and to exploit it for new developments [1]. Czarnecki’s book on Generative Programming is a good starting point to familiarize yourself with the topic of Domain Analysis and Domain Engineering.</p>
</div>
<div id="conclusions-and-further-work" class="section">
<h2>Conclusions and further work</h2>
<p>The only drawback of this approach is that special knowledge is necessary to model the DSL. It requires you to do some analysis of your application domain. A Feature Diagram can help you with this. Read the documentation on incidents, tickets, bug reports, or whatever they are named in your organization in order to learn the language of your business. Talk to business analysts and read the description of manual test cases &#8211; if they exist &#8211; in the area of your application domain. Start small and iterate. This means literally select just enough DSL commands to implement one test case. Implement another test case with the same commands and add additional commands as you go along. Do not hesitate to change the language to make it as human readable as possible. Collect early feedback from your domain experts. Avoid the capture and replay of test cases as much as possible. They are not easy to maintain and collecting too many of them will render your test suite useless. Instead break up the captured tests into reusable DSL commands.</p>
<p>If you know of a open source Python application that needs functional testing please let me know. I would be interested in executing functional test automation in a community project.</p>
<hr class="docutils" />
<p>[1] Krzysztof Czarnecki, Ulrich W. Eisenecker, 2000. Generative Programming &#8211; Methods, Tools, and Applications. Addison-Wesley.</p>
<p>[2] Z. R. Dai, 2006. An Approach to Model-Driven Testing &#8211; Functional and Real-Time Testing with UML 2.0, U2TP and TTCN-3. Fraunhofer Publications</p>
<p>[3] Arie van Deursen, Paul Klint, 2001. Domain-Specific Language Design Requires Feature Descriptions. Journal of Computing and Information Technology.</p>
<p>[4] Eric Evans, 2004. Domain-Driven Design &#8211; Tackling Complexity in the Heart of Software. Addison-Wesley.</p>
<p>[5] Mark Fink, 2008. Functional testing of web applications with Selenium. <a class="reference external" href="http://www.testing-software.org/cast/Webapp-Testing/Selenium.html">http://www.testing-software.org/cast/Webapp-Testing/Selenium.html</a>.</p>
<p>[6] Mark Fink, 2009. tdsl &#8211; A Functional Testing DSL. <a class="reference external" href="http://bitbucket.org/markfink/tdsl/">http://bitbucket.org/markfink/tdsl/</a>.</p>
<p>[7] Fitnesse acceptance testing framework. <a class="reference external" href="http://fitnesse.org/">http://fitnesse.org/</a>.</p>
<p>[8] Martin Fowler, 2008. Method Chaining. <a class="reference external" href="http://www.martinfowler.com/dslwip/">http://www.martinfowler.com/dslwip/</a>.</p>
<p>[9] Dan North, 2006. Introducing BDD, <a class="reference external" href="http://dannorth.net/introducing-bdd/">http://dannorth.net/introducing-bdd/</a>.</p>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/webapp-testing/webapp_testing_dsl.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Functional testing of web applications with Selenium</title>
		<link>http://www.testing-software.org/webapp-testing/selenium.html</link>
		<comments>http://www.testing-software.org/webapp-testing/selenium.html#comments</comments>
		<pubDate>Sat, 16 Jul 2011 14:06:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Webapp-Testing]]></category>
		<category><![CDATA[dsl]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[test automation]]></category>

		<guid isPermaLink="false">http://book.mark-fink.de/?p=101</guid>
		<description><![CDATA[Many tools for automated web testing are protocol drivers. These tools drive the tests through the HTTP protocol. This is in many cases suitable to test the server side of the application. For applications which heavily use Javascript this approach can not be taken. In the extreme as we see it with current AJAX applications [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div id="functional-testing-of-web-applications-with-selenium" class="section">
<h1><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">Many tools for automated web testing are protocol drivers. These tools drive the tests through the HTTP protocol. This is in many cases suitable to test the server side of the application. For applications which heavily use Javascript this approach can not be taken. In the extreme as we see it with current AJAX applications today the html page is only loaded once by the web client and after that all communication with the server is handled by Javascript completely. On top of that it is often required that those application supports multiple browsers. Because today browser implementations still handle Javascript and the DOM differently a protocol driver is relatively useless for testing and a application driver is needed.</span></h1>
<p>Selenium is a test tool which drives the test of a web application in the web browser. Selenium supports various browsers (IE, Firefox, Safari and most other browsers) on various platforms. The open source initiative around Selenium was started in 2004 by Jason Huggins.</p>
<p>Selenium is the type of tool you need in order to test the application in the browser in the way manual testers would. JavaScript and the DOM are covered by your Selenium tests.</p>
<div id="selenium-core" class="section">
<h2>Selenium Core</h2>
<p>Selenium Core is at heart a set of JavaScript code that executes tests which are contained in a HTMl table. Those tests life within the browser. The browser sees a test page which contains and drives your application. This is a simple concept but it is very effective and portable (to all the platforms mentioned above) at the same time.</p>
</div>
<div id="selenium-ide" class="section">
<h2>Selenium IDE</h2>
<p>Writing web application tests by hand without tool support is exhausting and almost impossible at lager scale. The tooling support you need is Selenium IDE. Selenium IDE is a Firefox extension for recording tests. It records all user interaction while browsing your application and you just need to add your verification steps while doing so.</p>
<p>The complete list of available selenium commands is available at Selenium Core TestRunner reference page:</p>
<p><a class="reference external" href="http://www.openqa.org/selenium-core/testrunner.html">http://www.openqa.org/selenium-core/testrunner.html</a></p>
<p>The following screenshot shows the Selenium IDE in action. A test case has been recorded. To resolve timing issues with execution of the JavaScript I had to insert a waitForElementPresent condition.</p>
<p><img style="width: 800px;" src="/wp-content/uploads/_images/Screenshot-Selenium_IDE2.png" alt="Record a test with Selenium IDE" /></p>
<p>Selenium IDE saves the testcase into a html table:</p>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/Screenshot-openstreetmap2.png" alt="HTML table contains test case" /></p>
<p>It is really just a plain HTML file:</p>
<div class="highlight-html">
<div class="highlight">
<pre><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns=</span><span class="s">"http://www.w3.org/1999/xhtml"</span> <span class="na">xml:lang=</span><span class="s">"en"</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head</span> <span class="na">profile=</span><span class="s">"http://selenium-ide.openqa.org/profiles/test-case"</span><span class="nt">&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">http-equiv=</span><span class="s">"Content-Type"</span> <span class="na">content=</span><span class="s">"text/html; charset=UTF-8"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"selenium.base"</span> <span class="na">href=</span><span class="s">""</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;title&gt;</span>openstreetmap<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;table</span> <span class="na">cellpadding=</span><span class="s">"1"</span> <span class="na">cellspacing=</span><span class="s">"1"</span> <span class="na">border=</span><span class="s">"1"</span><span class="nt">&gt;</span>
<span class="nt">&lt;thead&gt;</span>
<span class="nt">&lt;tr&gt;&lt;td</span> <span class="na">rowspan=</span><span class="s">"1"</span> <span class="na">colspan=</span><span class="s">"3"</span><span class="nt">&gt;</span>openstreetmap<span class="nt">&lt;/td&gt;&lt;/tr&gt;</span>
<span class="nt">&lt;/thead&gt;&lt;tbody&gt;</span>
<span class="nt">&lt;tr&gt;</span>
  <span class="nt">&lt;td&gt;</span>open<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>/<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr&gt;</span>
  <span class="nt">&lt;td&gt;</span>click<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>commit<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr&gt;</span>
  <span class="nt">&lt;td&gt;</span>type<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>query<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>Schmiechen<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr&gt;</span>
  <span class="nt">&lt;td&gt;</span>click<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>commit<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr&gt;</span>
  <span class="nt">&lt;td&gt;</span>waitForElementPresent<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>link=Schmiechen, Bayern<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr&gt;</span>
  <span class="nt">&lt;td&gt;</span>click<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>link=Schmiechen, Bayern<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr&gt;</span>
  <span class="nt">&lt;td&gt;</span>click<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;</span>link=Close<span class="nt">&lt;/td&gt;</span>
  <span class="nt">&lt;td&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;/tbody&gt;&lt;/table&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span></pre>
</div>
</div>
<p>In Selenium IDE select “File|Export Test Case as&#8230;|Python &#8211; Selenium RC” to export the test case to Python. You get the following Python script:</p>
<div class="highlight-python">
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">selenium</span>
<span class="kn">import</span> <span class="nn">unittest</span><span class="o">,</span> <span class="nn">time</span><span class="o">,</span> <span class="nn">re</span>

<span class="k">class</span> <span class="nc">NewTest</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span> <span class="o">=</span> <span class="n">selenium</span><span class="p">(</span><span class="s">"localhost"</span><span class="p">,</span> <span class="mi">4444</span><span class="p">,</span> <span class="s">"*firefox"</span><span class="p">,</span> <span class="s">"http://www.openstreetmap.org/"</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">test_new</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">sel</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s">"/"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"query"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">type</span><span class="p">(</span><span class="s">"query"</span><span class="p">,</span> <span class="s">"Schmiechen"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"commit"</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">60</span><span class="p">):</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">sel</span><span class="o">.</span><span class="n">is_element_present</span><span class="p">(</span><span class="s">"link=Schmiechen, Bayern"</span><span class="p">):</span> <span class="k">break</span>
            <span class="k">except</span><span class="p">:</span> <span class="k">pass</span>
            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s">"time out"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"link=Schmiechen, Bayern"</span><span class="p">)</span>
        <span class="n">sel</span><span class="o">.</span><span class="n">click</span><span class="p">(</span><span class="s">"link=Close"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">selenium</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">([],</span> <span class="bp">self</span><span class="o">.</span><span class="n">verificationErrors</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">unittest</span><span class="o">.</span><span class="n">main</span><span class="p">()</span></pre>
</div>
</div>
</div>
<div id="selenium-remote-control-rc" class="section">
<h2>Selenium Remote Control (RC)</h2>
<p>The Selenium RC provides a proxy server in order to treat the web application in a way that the browser thinks that the Selenium Core JavaScript files have the same origin as the web application. As a consequence the “same origin policy” of the browser is not violated.</p>
<p>Run the server part of Selenium RC with “java -jar selenium-server.jar”. This is often also called Selenium Server.</p>
<p>Now we can easily execute the test case:</p>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/TestUseMap2.png" alt="Execute the test case" /></p>
<p>It takes additional overhead (~25 sec) to prepare the profile and launch the browser.</p>
</div>
<div id="selenium-grid" class="section">
<h2>Selenium Grid</h2>
<p>Selenium Grid is a platform to support parallel execution of test cases. The grid consists of multiple machines each running its own Selenium Server. Through parallel execution the completion time of automated web application testing can be drastically reduced.</p>
<p>You will find more information on Selenium Grid and “Web Testing That Doesn’t Take Hours!”:</p>
<p><a class="reference external" href="http://selenium-grid.openqa.org/">http://selenium-grid.openqa.org/</a></p>
</div>
<div id="installation" class="section">
<h2>Installation</h2>
<p>Selenium IDE is a Firefox plugin. Open Firefox and select “Tools|add-ons|Get Add-ons”. Search for Selenium IDE and select “Add to Firefox”.</p>
<p>Everything else you usually need is in Selenium RC. Get the latest snapshot from:</p>
<p><a class="reference external" href="http://selenium-rc.openqa.org/download.html">http://selenium-rc.openqa.org/download.html</a></p>
<p>At time of writing the latest snapshot resolved some issues with Firefox 3 on Ubuntu and OS X. Unpack the “selenium-python-client-driver” somewhere on your PYTHONPATH. You also need the selenium-server.jar to run the server part of Selenium RC.</p>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/webapp-testing/selenium.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working with legacy code</title>
		<link>http://www.testing-software.org/tools/code-reading.html</link>
		<comments>http://www.testing-software.org/tools/code-reading.html#comments</comments>
		<pubDate>Sat, 16 Jul 2011 14:01:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[development]]></category>

		<guid isPermaLink="false">http://book.mark-fink.de/?p=99</guid>
		<description><![CDATA[When working in QA or Test Automation you are much more likely to be confronted with a legacy application with hundreds of thousands of code lines with missing documentation and test cases than finding well documented one with high test coverage and beautiful code. In many cases the legacy code has to be re-factored to [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div id="working-with-legacy-code" class="section">
<h1><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">When working in QA or Test Automation you are much more likely to be confronted with a legacy application with hundreds of thousands of code lines with missing documentation and test cases than finding well documented one with high test coverage and beautiful code. In many cases the legacy code has to be re-factored to improve testability. Therefore one critical skill is to be able to work with legacy code.</span></h1>
<p>When I start reading source code I start from a birds eye perspective. I first want to know how big the project is I am looking at.</p>
<p>Loc comes in handy in this situation to get a first general impression about the scale of the code base.</p>
<div id="measuring-lines-of-code-loc" class="section">
<h2>Measuring <em>Lines Of Code</em> (LOC)</h2>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo apt-get install sloccount
<span class="nb">cd </span>sloccount openerp-server-5.0.0_rc3

SLOC        Directory       SLOC-by-Language <span class="o">(</span>Sorted<span class="o">)</span>
58241   addons-extra    <span class="nv">python</span><span class="o">=</span>50644,php<span class="o">=</span>7434,sh<span class="o">=</span>163
53168   addons          <span class="nv">python</span><span class="o">=</span>53126,php<span class="o">=</span>42
22288   server          <span class="nv">python</span><span class="o">=</span>22287,sh<span class="o">=</span>1
15599   client          <span class="nv">python</span><span class="o">=</span>15599
12334   web             <span class="nv">python</span><span class="o">=</span>12205,sh<span class="o">=</span>129
72      top_dir         <span class="nv">python</span><span class="o">=</span>72

Totals grouped by language <span class="o">(</span>dominant language first<span class="o">)</span>:
python:      153933 <span class="o">(</span>95.20%<span class="o">)</span>
php:           7476 <span class="o">(</span>4.62%<span class="o">)</span>
sh:             293 <span class="o">(</span>0.18%<span class="o">)</span></pre>
</div>
</div>
</div>
<div id="measuring-complexity-mccabe" class="section">
<h2>Measuring complexity (McCabe)</h2>
<p>Another very useful code metric in the situation described above is the McCabe complexity metric. This tool helps you to identify the most complex code. The complex areas need the most attention when it comes to quality assurance measures (documentation, testing, etc.). These areas usually contain the most defects, too.</p>
<div class="highlight-sh">
<div class="highlight">
<pre><span class="c">#manually extract tarball</span>
PyMetrics.py program.py</pre>
</div>
</div>
</div>
<div id="understanding-the-code-structure-using-callgraphs" class="section">
<h2>Understanding the code structure using Callgraphs</h2>
<p>Almost every time I am approaching a code base unknown to me I am looking for a certain functionality which I am particularly interested in. As soon as I understand the functionality I go to the next one and so on until I understand everything I need to. To identify relevant parts in the code a call graph proved to be very handy. The graph “lists” all the relevant modules and functions and shows in which order they are called. I always use the call graph as a “map” that helps me to navigate the code base unknown to me.</p>
<div id="installation-of-the-pycallgraph-tool-in-ubuntu" class="section">
<h3>Installation of the pycallgraph tool (in Ubuntu)</h3>
<div class="highlight-sh">
<div class="highlight">
<pre>apt-get install pycallgraph</pre>
</div>
</div>
<p>Instead of starting your program with your python interpreter you just use pycallgraph to execute your script. For example run the scotch recording proxy within the pycallgraph tool:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>pycallgraph run-recording-proxy -i scotch.* -e *.*</pre>
</div>
</div>
<p>Call graphs get big very fast because the program usually calls a lot of library functions. For that reason I <em>excluded</em> everything except the scotch module from the diagram (-i and -e options), which I <em>included</em>.</p>
<p><img style="width: 600px;" src="Tools/pycallgraph.png" alt="Pycallgraph of the scotch recording proxy" /></p>
</div>
<div id="printing-the-callgraph" class="section">
<h3>Printing the callgraph</h3>
<p>Callgraphs are usually big especially if you are working with a non trivial module. To be able to print those callgraphs in case you do not have a plotter the program Dia (Diagrams, UML, etc.) comes in very handy. To install it on a Ubuntu box just type:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo apt-get install dia</pre>
</div>
</div>
<p>Dia helps you to split huge visualizations graphics into multiple pages that you then print separately.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/tools/code-reading.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Howto set up a SSL test site with Apache2</title>
		<link>http://www.testing-software.org/tools/ssl_client_authentication.html</link>
		<comments>http://www.testing-software.org/tools/ssl_client_authentication.html#comments</comments>
		<pubDate>Sat, 16 Jul 2011 13:59:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://book.mark-fink.de/?p=95</guid>
		<description><![CDATA[For testing purposes I needed to set up a SSL site which makes use of both client and server certificates. Of course I do not want to spend money on certificates I use in a testing environment. Therefore I need to create and sign my own certificates. I found lots of configuration samples, websites and [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div id="howto-set-up-a-ssl-test-site-with-apache2" class="section">
<h1><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">For testing purposes I needed to set up a SSL site which makes use of both client and server certificates. Of course I do not want to spend money on certificates I use in a testing environment. Therefore I need to create and sign my own certificates. I found lots of configuration samples, websites and blogs on the topic &#8211; unfortunately none had the complete setup I needed. To make things worse most of the howto’s I have found ware incompatible because of different ways on how to approach the Apache2 configuration. That is the reason why I decided to write a short howto myself which I hope you will find useful.</span></h1>
<p>Most of the Apache2 configuration I borrowed from this howto:</p>
<p><a class="reference external" href="http://techxplorer.com/2009/04/27/using-apache-and-ubuntu-for-local-websites-with-ssl/">http://techxplorer.com/2009/04/27/using-apache-and-ubuntu-for-local-websites-with-ssl/</a></p>
<p>We are building a sample site which you access in your browser with the following url:</p>
<p><a class="reference external" href="https://my.sample.com">https://my.sample.com</a></p>
<div id="apache2-setup-and-installation" class="section">
<h2>Apache2 setup and installation</h2>
<p>First of all you need Apache2 installed (for Ubuntu):</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo apt-get install apache2</pre>
</div>
</div>
<p>If you want to make it really pretty (what I usually want to do) put the following FQDN into your /etc/hosts configuration (you probably have to restart your browser to make this work):</p>
<div class="highlight-text">
<div class="highlight">
<pre>127.0.2.1   my.sample.com</pre>
</div>
</div>
<p>Any requests for the my.sample.com domain, which does not exit on the internet, will be sent to the 127.0.2.1 IP address (part of the loopback).</p>
<p>Start a new file in the /etc/apache/sites-available directory with the name of the site, for example: my.sample.com. Use this configuration as a starting point and change the IP Address, ServerName, ServerAdmin, DocumentRoot and Directory as appropriate.</p>
<div class="highlight-xml">
<pre>&lt;VirtualHost 127.0.2.1:443&gt;
    ServerName my.sample.com
    ServerAdmin admin@sample.com

    DocumentRoot /home/mark/devel/tam/build
    &lt;Directory /&gt;
        Options FollowSymLinks
        AllowOverride None
    &lt;/Directory&gt;
    &lt;Directory /home/mark/devel/tam/build&gt;
        Options Indexes FollowSymLinks Multiviews
        AllowOverride all
        Order allow,deny
        allow from all
    &lt;/Directory&gt;

    ErrorLog /var/log/apache2/error.log

    LogLevel warn

    CustomLog /var/log/apache2/access.log combined
&lt;/VirtualHost&gt;</pre>
</div>
<p>Execute the following command to enable the new site:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo a2ensite my.sample.com</pre>
</div>
</div>
<p>Restart Apache by executing the following command:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo /etc/init.d/apache2 restart</pre>
</div>
</div>
<p>Test the new website:</p>
<p>Put a sample file (index.html or something like that) into the document root and check that it is visible using your browser.</p>
</div>
<div id="adding-ssl-to-the-site" class="section">
<h2>Adding SSL to the site</h2>
<p>In order to create certificates you need openssl and some configuration which is described in this section. If you want you can just install the provided sample certificates instead of creating your own (the certificates are contained in testing-software/ssh-sniffer). If you want to skip the certificate creation just jump to install certificates. Make sure you use this only as a local test scenario!</p>
<p>Install or upgrade openssl (in Ubuntu):</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo apt-get install openssl</pre>
</div>
</div>
<p>In order to use the steps provided below you have to configure openssl (/etc/ssl/openssl.cfg).</p>
<div class="highlight-text">
<div class="highlight">
<pre>#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#

# This definition stops the following lines choking if HOME isn't
# defined.
HOME            = .
RANDFILE        = $ENV::HOME/.rnd

# Extra OBJECT IDENTIFIER info:
#oid_file       = $ENV::HOME/.oid
oid_section     = new_oids

# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
# extensions    =
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)

[ new_oids ]

# We can add new OIDs in here for use by 'ca' and 'req'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6

####################################################################
[ ca ]
default_ca      = sampleCA           # The default ca section

####################################################################
[ sampleCA ]

dir             = ./CA               # Where everything is kept
certs           = $dir/certs         # Where the issued certs are kept
crl_dir         = $dir/crl           # Where the issued crl are kept
database        = $dir/index.text     # database index file.
#unique_subject = no                 # Set to 'no' to allow creation of
                                     # several certificates with same subject.
new_certs_dir   = $dir               # default place for new certs.

certificate     = $dir/sampleCA.crt  # The CA certificate
serial          = $dir/serial        # The current serial number
crlnumber       = $dir/crlnumber     # the current crl number
                                     # must be commented out to leave a V1 CRL
crl             = $dir/sampleCA.crl  # The current CRL
private_key     = $dir/sampleCA.key  # The private key
RANDFILE        = $dir/private/.rand # private random number file

x509_extensions = usr_cert           # The extensions to add to the cert
...</pre>
</div>
</div>
<div id="create-ca" class="section">
<h3>Create CA</h3>
<p>We need to create own CA certificate and CA key, which we will use to sign our web server and our client certificates.</p>
<p>When starting out with a new CA we need to create the following directories/ subdirectories:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>mkdir ./sampleCA

mkdir ./sampleCA/CA

mkdir ./sampleCA/CA/newcerts

mkdir ./sampleCA/CA/certs

mkdir ./sampleCA/CA/crl

mkdir ./sampleCA/CA/private</pre>
</div>
</div>
<p>and the files:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>touch ./sampleCA/CA/index.text

touch ./sampleCA/CA/serial

<span class="nb">echo</span> <span class="s2">"01"</span> &gt; ./sampleCA/CA/serial

<span class="nb">cd</span>  ./sampleCA</pre>
</div>
</div>
<p>Create CA key with 1024 bit:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl genrsa -out ./CA/sampleCA.key</pre>
</div>
</div>
<p>Create CA Certificate Request:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl req -new -key ./CA/sampleCA.key -out ./CA/sampleCA.csr</pre>
</div>
</div>
<p>Self-sign CA certificate:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl x509 -req -days 365 -in ./CA/sampleCA.csr -out ./CA/sampleCA.crt -signkey ./CA/sampleCA.key</pre>
</div>
</div>
<p>Now we finally have our CA certificate and our CA key, which we will use to sign our webserver and our client certificates.</p>
<p>Check the CA certificates content:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl x509 -in ./CA/sampleCA.crt -text</pre>
</div>
</div>
</div>
<div id="create-the-web-server-certificates" class="section">
<h3>Create the web server certificates</h3>
<p>For the web server we need to provide the server side certificate and key.</p>
<p>Create the web server key:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl genrsa -des3 -out sampleWebServer.key

<span class="o">(</span>pass phrase: test123<span class="o">)</span></pre>
</div>
</div>
<p>Remove the pass phrase from the web server key otherwise Apache2 will always prompt you for the pass phrase at server startup. Which is a real problem if you want to keep the configuration running.</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl rsa -in sampleWebServer.key -out sampleWebServer.key</pre>
</div>
</div>
<p>The “-des3” option tell openssl to encrypt the key with a 3DES (Triple-DES) Pass-phrase. For later, this will be the startup pass-phrase for our webserver certificate. Always keep the pass phrases in mind or keep it in a save place!</p>
<p>Now create the web server certificate request:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl req -new -key sampleWebServer.key -out sampleWebServer.csr</pre>
</div>
</div>
<p>IMPORTANT NOTE: During the creation process you will be asked several questions, e.g. the “Common Name” (=CN). As the CN has no default value in openssl.cnf you MUST enter the complete webserver’s name (FQDN=Fully Qualified Domain Name), For example my.sample.com!!! This string will be later compared by Apache to the config directive “ServerName”. If these strings are not identical, the webserver will not be able to start up!</p>
<p>Sign the web servers certificate request with the CA key:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl ca -in sampleWebServer.csr -cert ./CA/sampleCA.crt -keyfile ./CA/sampleCA.key -out sampleWebServer.crt</pre>
</div>
</div>
<p>Check the generated certificate if you want:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl x509 -in sampleWebServer.crt -text</pre>
</div>
</div>
</div>
<div id="install-the-certificates-and-samplewebserver-key-on-your-machine" class="section">
<h3>Install the certificates and sampleWebServer key on your machine</h3>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo cp sampleWebServer.key /etc/ssl/private/

sudo chmod 400 /etc/ssl/private/sampleWebServer.key

sudo cp sampleWebServer.crt /etc/ssl/certs/

sudo cp ./CA/sampleCA.crt /etc/ssl/certs/</pre>
</div>
</div>
</div>
<div id="reconfigure-apache-to-use-ssl" class="section">
<h3>Reconfigure Apache to use SSL</h3>
<p>Enable the ssl module with the following command:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo a2enmod ssl</pre>
</div>
</div>
<p>Use the following configuration as a starting point and add the necessary configuration lines to the configuration file we made before. Change the IP Address, ServerName, ServerAdmin, DocumentRoot and Directory as appropriate.</p>
<div class="highlight-xml">
<pre>&lt;IfModule mod_ssl.c&gt;
&lt;VirtualHost 127.0.2.1:443&gt;
    ServerName my.sample.com
    ServerAdmin admin@sample.com

    DocumentRoot /home/mark/devel/tam/build
    &lt;Directory /&gt;
        Options FollowSymLinks
        AllowOverride None
    &lt;/Directory&gt;
    &lt;Directory /home/mark/devel/tam/build&gt;
        #SSLRequireSSL
        #SSLRequire %{SSL_CLIENT_S_DN_O}  eq "Internet Widgits Pty Ltd"
        Options Indexes FollowSymLinks Multiviews
        AllowOverride all
        Order allow,deny
        allow from all
   &lt;/Directory&gt;

    ErrorLog /var/log/apache2/error.log

    LogLevel warn

    CustomLog /var/log/apache2/access.log combined

    # SSL
    SSLEngine on

    # Server Certificate
    SSLCertificateFile /etc/ssl/certs/sampleWebServer.crt
    SSLCertificateKeyFile /etc/ssl/private/sampleWebServer.key

    #SSLCACertificateFile /etc/ssl/certs/sampleCA.crt
    #SSLVerifyClient require
    #SSLVerifyDepth 2

    BrowserMatch ".*MSIE.*"\
        nokeepalive ssl-unclean-shutdown \
        downgrade-1.0 force-response-1.0
&lt;/VirtualHost&gt;
&lt;/IfModule&gt;</pre>
</div>
<p>Restart Apache:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo /etc/init.d/apache2 restart

<span class="o">(</span>you probably have to provide the pass phrase test123<span class="o">)</span></pre>
</div>
</div>
<p>Test the new website and enter the following URL into your browser:</p>
<p><a class="reference external" href="https://my.sample.com">https://my.sample.com</a></p>
<p>(you probably have to add a security exception for the server certificate to your web browser in order to access your site &#8211; your browser will prompt you accordingly)</p>
<p>Make sure that you use https and not just http!</p>
</div>
</div>
<div id="create-client-certificate-and-enforce-client-authentication-by-the-server" class="section">
<h2>Create client certificate and enforce client authentication by the server</h2>
<p>In order to use client authentication you need a client certificate to be installed with your browser. Please note that your CA certificate which is needed to verify the client certificate has already been installed on the server.</p>
<div id="create-the-client-certificate" class="section">
<h3>Create the client certificate:</h3>
<p>We use openssl to create the client certificate, too.</p>
<div class="highlight-sh">
<div class="highlight">
<pre><span class="nb">cd</span> ./sampleCA</pre>
</div>
</div>
<p>Create the client key:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl genrsa -des3 -out client.key 1024

<span class="o">(</span>pass phrase: test123<span class="o">)</span></pre>
</div>
</div>
<p>Create user certificate request:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl req -new -key client.key -out client.crs

<span class="o">(</span>This <span class="nb">time </span>we enter <span class="k">for </span>the common name <span class="o">(</span>CN<span class="o">)</span> our full name, <span class="k">for </span>example <span class="s2">"client"</span><span class="o">)</span></pre>
</div>
</div>
<p>Sign user certificate request and create certificate:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl ca -in client.crs -cert ./CA/sampleCA.crt -keyfile ./CA/sampleCA.key -out client.crt</pre>
</div>
</div>
<p>Convert user certificate to p12 format:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12</pre>
</div>
</div>
<p>In case you also need the pem format (containing both private key and certificate):</p>
<div class="highlight-sh">
<div class="highlight">
<pre>openssl pkcs12 -in client.p12 -out client.pem -nodes</pre>
</div>
</div>
</div>
<div id="enforce-client-authentication-on-the-server-side" class="section">
<h3>Enforce client authentication on the server side</h3>
<p>At the moment, our Apache webserver accepts any SSL connection. Therefore we have to force him to cross-check whether the presented user certificate is valid. You can further enhance security by evaluating that the client certificate matches certain conditions. For example to match the company name.</p>
<p>To make this happen, please uncomment the following Apache configuration options in your my.sample.com file:</p>
<div class="highlight-text">
<div class="highlight">
<pre>SSLRequireSSL

SSLRequire %{SSL_CLIENT_S_DN_O}  eq "Internet Widgits Pty Ltd"

and:

SSLCACertificateFile /etc/ssl/certs/sampleCA.crt

SSLVerifyClient require

SSLVerifyDepth 2</pre>
</div>
</div>
<p>Restart the Apache2 web server:</p>
<div class="highlight-sh">
<div class="highlight">
<pre>sudo /etc/init.d/apache2 restart

<span class="o">(</span>you probably have to provide the pass phrase test123<span class="o">)</span></pre>
</div>
</div>
<p>Please verify that you can not access the website without the client certificate.</p>
<p><img style="width: 400px;" src="/wp-content/uploads/_images/User-Identification-Request2.png" alt="Select the client certificate for authentication in browser" /></p>
</div>
<div id="import-the-client-certificate-into-your-browser" class="section">
<h3>Import the client certificate into your browser</h3>
<p>From now on your browser needs to provide a valid client certificate in order to access the website. In order to import the client.p12 certificate (it is contained in the ./sampleCA folder) follow the instructions.</p>
<p>In Firefox navigate through the menu structure:</p>
<div class="highlight-text">
<div class="highlight">
<pre>Edit &gt; Preferences &gt; Advanced &gt; View Certificates &gt; Your Certificates -&gt; Import -&gt; Choose file

(I did not set any password)</pre>
</div>
</div>
<p>Verify that you now are able to access your site again. Well done!</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/tools/ssl_client_authentication.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java Garbage Collection Analysis and Tuning</title>
		<link>http://www.testing-software.org/tools/gcview.html</link>
		<comments>http://www.testing-software.org/tools/gcview.html#comments</comments>
		<pubDate>Sat, 16 Jul 2011 13:55:51 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[heap]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jvm]]></category>

		<guid isPermaLink="false">http://book.mark-fink.de/?p=91</guid>
		<description><![CDATA[Nowadays in many cases the root cause for non-performing Java applications is the suboptimal configuration for memory usage and garbage collection. The situation is even more complicated since the optimal heap configuration in most cases can neither be calculated nor guessed. The optimal configuration depends on the size of the objects and their lifespan and [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div id="java-garbage-collection-analysis-and-tuning" class="section">
<h1><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">Nowadays in many cases the root cause for non-performing Java applications is the suboptimal configuration for memory usage and garbage collection. The situation is even more complicated since the optimal heap configuration in most cases can neither be calculated nor guessed. The optimal configuration depends on the size of the objects and their lifespan and those depend on the (type of) application and the user behaviour. What? Did you just say that the optimal configuration depends on the user behaviour?? Yes, that’s true! Basically what I want to say is that optimizing the heap configuration is not a one shot operation. You will not be able to set it right once and forget about it. You should re-evaluate your application on a regular basis and check if you have to adapt your JVM configuration to match changed circumstances. On the other hand the JVM is very forgiving and your application will perform very well with a less than optimal heap configuration.</span></h1>
<div id="introduction" class="section">
<h2>Introduction</h2>
<p>I order to optimize the heap configuration for your situation you have to try different settings. Usually in order to do so you need some kind of test environment and a load generator which is able to produce realistic load patterns in a repeatable way. With this setup you can try different heap configurations and monitor the heap utilization and garbage collector. Best practice is to make an educated guess on the configuration and start optimizing from there. In this article I will show you how to do this.</p>
</div>
<div id="java-memory-management" class="section">
<h2>Java Memory Management</h2>
<p>In order to being able to optimize the heap utilization of your application you need to understand how the Java heap and garbage collector work and how they are configured.</p>
<p>The heap is split up in Young-Generation (Eden-Space, and two Survivor-Spaces of identical size usually called From and To), Old Generation (Tenured) and Permanent Space.</p>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/generations.png" alt="Heap organization in Eden-, two Survivor-, Tenured-, and Perm-Spaces" /></p>
<p>The idea behind this organization of the heap is that most of the objects dye in New-Space because they have a very short life cycle:</p>
<ul class="simple">
<li>80-98% of all new instantiated objects dye within the next million of instructions.</li>
<li>80-98% of all new instantiated objects dye before an additional Megabyte of storage is allocated.</li>
</ul>
<p>To clean up the whole heap within one garbage collector run would take much longer than reducing the cleaning up to just the Young-Generation (Minor-GC). Only the Full-Gc works on the complete heap. Usually a Minor-Gc is much faster than a Full-Gc. The execution time of a Gc run is very important to you because most garbage collection strategies stop the world. This means that even if you have multiple processor cores, all execution is halted during GC run. The stop-the-world strategies have many negative effects on applications that optimize response times. Today most JVMs also provide an implementation of a mark-and-sweep strategy which eliminates the negative effects because they do not need long pauses.</p>
</div>
<div id="heap-configuration-parameters" class="section">
<h2>Heap configuration parameters</h2>
<p>The next step before you can start optimizing the Java heap and garbage collector configuration is to develop a thorough understanding of the configuration parameters.</p>
<dl class="docutils">
<dt><cite>-Xms</cite></dt>
<dd>defines the minimal/ initial size of the heap</dd>
<dt><cite>-Xmx</cite></dt>
<dd>defines the maximum size of the heap</dd>
</dl>
<p>For server applications you should set both parameters identical because the resizing of the heap also initiates a Full-Gc. With an application under load this could have a severe impact on application performance from the very start. On most operating systems the regained memory is not returned to the operating system.</p>
<dl class="docutils">
<dt><cite>-XX:NewSize</cite></dt>
<dd>initial size of the New Space. This includes Eden plus two Survivour Spaces (From and To).</dd>
<dt><cite>-XX:MaxNewSize</cite></dt>
<dd>usually we set -XX:MaxNewSize the same as -XX:NewSize because resizing would cause a full collection</dd>
<dt><cite>-XX:PermSize</cite></dt>
<dd>initial size of the Perm Space</dd>
<dt><cite>-XX:MaxPermSize</cite></dt>
<dd>usually we set -XX:MaxPermSize the same as -XX:PermSize because resizing would cause a full collection</dd>
<dt><cite>-XX:SurvivorRatio</cite></dt>
<dd>ratio Eden to Survivor-Space; I usually start with a survivor ratio of 8; in this case each of the survivor spaces (From and To) uses 1/10 of the size of the New-Space</dd>
<dt><cite>-XX:NewRatio</cite></dt>
<dd>ratio between old and new generation</dd>
<dt><cite>-XX:MaxPermSize</cite></dt>
<dd>size of the Permanent Generation</dd>
<dt><cite>-XX:TargetSurvivorRatio=90</cite></dt>
<dd>the survivor space can be filled by 90% until the objects are moved to old generation</dd>
<dt><cite>-XX:MaxTenuringThreshold</cite></dt>
<dd>number of from-to runs until object is moved to old generation</dd>
</dl>
</div>
<div id="gc-algorithms" class="section">
<h2>GC Algorithms</h2>
<p>Over time Sun developed different strategies for the garbage collector. Different applications have different requirements regarding response times. In case you optimize for response times or you are having realtime requirements you are in a totally different situation than somebody who is optimizing for throughput. In this section I describe the different strategies for you so that you will be able to select the one that fits best to your needs. Different strategies and configuration options are available in the different JVM versions. Check the version of your JVM before you start working.</p>
<div id="garbage-collection-of-the-young-generation" class="section">
<h3>Garbage collection of the Young-Generation</h3>
<p>When the garbage collector runs all referenced objects in Eden-Space and From-Survivor are copied into the To-Survivor. During this operation objects that already have been kept for some time in the Survivor spaces are moved into the Old-Generation. After that Eden-Space and From-Survivor are emptied and From- and To- Survivor spaces switch their functions. Are more objects referenced than fit into From-Survivor the remaining objects are directly moved into the Old-Generation. After garbage collection of the Young-Generation is finished both Eden-Space and To-Survivor are empty.</p>
</div>
<div id="garbage-collection-in-old-and-permanent-generations" class="section">
<h3>Garbage collection in Old- and Permanent- Generations</h3>
<p>For clean-up of the Old- and Perm- generations a mark-and-sweep algorithm is used. During the mark phase all objects that are referenced by active objects (for example active thread objects, system classes, local variables, pending exceptions, references of the native stack). The removal of the unmarked objects takes place in the sweep phase. After completion of the sweep phase the markings are removed. The memory is now fragmented. During the compaction phase all remaining objects are moved to the beginning of the generation in order to get a continuous free memory region. This simplifies the allocation of memory for new objects.</p>
<p>TODO: describe other strategies</p>
<ul class="simple">
<li>Parallel GC</li>
<li>Concurrent Mark Sweep</li>
<li>Parallel Compaction</li>
</ul>
</div>
</div>
<div id="analysis-of-the-memory-utilization" class="section">
<h2>Analysis of the memory utilization</h2>
<p>After you decided for the initial configuration for heap and garbage collector you will use a load tool to put your application under realistic load (depending on your application this takes usually 8-10 hours). In order to decide for improvements you need to analyse the memory utilization under load. Many monitoring tools also provide monitoring for the Java memory utilization. Call me old-fashioned but I do not trust them. Many of them have weird algorithms to calculate the values you are dependant on for your optimization. I have seen their inaccuracy so many times. Therefore I recommend to log the garbage collector information to a logfile (usually you will do this anyway). After your test run is complete you extract the data for your analysis from the logfile.</p>
<p>important: <em>look at the frequency and time consumed by gc</em></p>
<div id="jvm-configuration-for-additional-logging-about-the-heap-utilization" class="section">
<h3>JVM configuration for additional logging about the heap utilization</h3>
<p>The JVM provides a lot of different options to provide log information about heap utilization and garbage collector performance.</p>
<dl class="docutils">
<dt><cite>-verbose:gc</cite></dt>
<dd>get detailed information about GC measures and durations. Also required when additional options for GC logging are configured</dd>
<dt><cite>-XX:+PrintGCTimeStamps</cite></dt>
<dd>add timestamps at the beginning of the Gc entries</dd>
<dt><cite>-Xloggc:filename</cite></dt>
<dd>use a dedicated logfile for Gc information</dd>
<dt><cite>-XX:+PrintGCDetails</cite></dt>
<dd>extract size of young an old generation before and after gc, total heap, time consumption</dd>
<dt><cite>-XX:+PrintHeapAtGC</cite></dt>
<dd>more information regarding heap size before and after gc</dd>
<dt><cite>-XX:+PrintTenuringDistribution</cite></dt>
<dd>adds tenuring information if you want to analyse the sizes of Eden- and Survivor-Spaces</dd>
<dt><cite>-XX:+PrintHeapUsageOverTime</cite></dt>
<dd>add heap usage and capacity with timestamps</dd>
<dt><cite>-XX:+PrintTLAB</cite></dt>
<dd>add thread local allocation buffers (TLAB)</dd>
</dl>
</div>
</div>
<div id="tools" class="section">
<h2>Tools</h2>
<p>This section gives a brief overview of some tools that assist you in analysing the heap utilization of your JVM. Depending on your environment a particular tool could be more suitable than others. Currently there are many hundreds of tools available and there is no way that this section could provide a comprehensive overview of tool situation. Nevertheless it is intended to give a brief overview of different approaches and to reference supportive tools.</p>
<div id="visualgc" class="section">
<h3>Visualgc</h3>
<p>Instant visual analysis of GC by sun. Visualgc directly connects to the JVM of your running application. There is no need to output the information into a logfile.</p>
<p>Visualgc is not included in the jdk any more. So download it from <a class="reference external" href="http://java.sun.com/performance/jvmstat/">http://java.sun.com/performance/jvmstat/</a></p>
<p>In order to install it on Ubuntu uncompress the download to /usr/local/bin.</p>
<p>Edit ~/.bashrc in order to add the following two lines:</p>
<div class="highlight-text">
<div class="highlight">
<pre>export JVMSTAT_JAVA_HOME='/usr/lib/jvm/java-6-sun'
PATH=$PATH:/usr/local/bin/jvmstat/bin</pre>
</div>
</div>
<p>Run jps in order to look up the JVM id of your running application:</p>
<div class="highlight-text">
<div class="highlight">
<pre>#jps
9599 Jps
9590 Life

#visualgc 9590</pre>
</div>
</div>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/Screenshot-visualgc.png" alt="Connect visualgc to your application JVM to analyse garbage collection" /></p>
</div>
<div id="gcview" class="section">
<h3>gcview</h3>
<p>For me in most cases connecting to the JVM with visualgc is not an option for various reasons. Mostly I run lots of performance tests and most of them have long durations 4-10 hours. Therefore I prefer to collect logfiles after the test has been completed and analyse them during post-processing. For the analysis of logfiles I maintain a Python script which recently had a complete overhaul.</p>
<p>To log information about heap utilization into a logfile the JVM offers you several parameters (see above). For the analysis I describe here I recommend the following configuration in addition to the memory configuration parameters:</p>
<div class="highlight-text">
<div class="highlight">
<pre>-verbose:gc -XX:+PrintGCTimeStamps
-XX:-TraceClassUnloading -XX:+PrintHeapAtGC</pre>
</div>
</div>
<p>The Python script that produces the diagrams for Gc analysis I used in this article you will find here together with a sample Java application for heap utilization: <a class="reference external" href="http://bitbucket.org/markfink/testing-software/src/tip/gcview/">http://bitbucket.org/markfink/testing-software/src/tip/gcview/</a></p>
</div>
<div id="jstat" class="section">
<h3>Jstat</h3>
<p>The jstat utility is a statistics monitoring tool. It attaches to a Java VM and collects and logs performance statistics as specified by the command line options.</p>
<p>The jstat utility does not require the Java VM to be started with any special options. This utility is included in the JDK.<br />
The following table lists the jstat command options.</p>
<table class="docutils option-list" frame="void" rules="none">
<colgroup>
<col class="option" />
<col class="description" /></colgroup>
<tbody valign="top">
<tr>
<td class="option-group"><kbd><span class="option">-c<var>lass</var></span></kbd></td>
<td>prints statistics on the behaviour of the class loader</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-c<var>ompiler</var></span></kbd></td>
<td>prints statistics on the behaviour of the Java compiler</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>c</var></span></kbd></td>
<td>prints statistics on the behaviour of the garbage collected heap</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>ccapacity</var></span></kbd></td>
<td>prints statistics of the capacities of the generations and their corresponding spaces</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>ccause</var></span></kbd></td>
<td>prints the summary of garbage collection statistics with the cause of the last and current (if applicable) garbage collection events</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>cnew</var></span></kbd></td>
<td>prints statistics of the behaviour of the new generation</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>cnewcapacity</var></span></kbd></td>
<td>prints statistics of the sizes of the new generations and their corresponding spaces</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>cold</var></span></kbd></td>
<td>prints statistics of the behaviour of the old and permanent generations</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>coldcapacity</var></span></kbd></td>
<td>prints statistics of the sizes of the old generation</td>
</tr>
<tr>
<td class="option-group" colspan="2"><kbd><span class="option">-g<var>cpermcapacity</var></span></kbd></td>
</tr>
<tr>
<td></td>
<td>prints statistics of the sizes of the permanent generation</td>
</tr>
<tr>
<td class="option-group"><kbd><span class="option">-g<var>cutil</var></span></kbd></td>
<td>prints a summary of garbage collection statistics</td>
</tr>
<tr>
<td class="option-group" colspan="2"><kbd><span class="option">-p<var>rintcompilation</var></span></kbd></td>
</tr>
<tr>
<td></td>
<td>prints Java compilation method statistics</td>
</tr>
</tbody>
</table>
<p>A complete description of the jstat options plus examples, can be found at:<br />
<a class="reference external" href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html">http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html</a></p>
<p>The following demonstrates the jstat command which attaches to pid 16945 and takes five samples at 250 millisecond intervals. The -gcnew option specifies that statistics of the behaviour of the new generation is output.</p>
<div class="highlight-text">
<div class="highlight">
<pre># jps
16945 Life
16954 Jps
# jstat -gcnew 16945 250 5
    S0C     S1C    S0U     S1U TT MTT     DSS       EC       EU    YGC     YGCT
48000.0 48000.0    0.0 48000.0  1  15 24000.0 672000.0 109709.5      1    0.623
48000.0 48000.0    0.0 48000.0  1  15 24000.0 672000.0 123418.2      1    0.623
48000.0 48000.0    0.0 48000.0  1  15 24000.0 672000.0 137127.0      1    0.623
48000.0 48000.0    0.0 48000.0  1  15 24000.0 672000.0 150835.8      1    0.623
48000.0 48000.0    0.0 48000.0  1  15 24000.0 672000.0 164544.6      1    0.623</pre>
</div>
</div>
</div>
<div id="hpjmeter" class="section">
<h3>HPJmeter</h3>
<p>Former JTune is now included in HPJmeter (please do not confuse it with the Jmeter open source performance testing tool). You can either connect directly to a running server or read from a logfile. To be able to connect directly you will need to start an agent with your application. The HPJmeter user guide describes how to do this: <a class="reference external" href="http://docs.hp.com/en/5992-5899/index.html">http://docs.hp.com/en/5992-5899/index.html</a>.</p>
<p>What makes HPJmeter particularly interesting for me is that you can read Gc logs with it.</p>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/Screenshot-hpjmeter.png" alt="HPJmeter analyses Gc logfiles" /></p>
<p>HPJmeter also brings with it a comprehensive help which describes Gc concepts and metrics in detail.</p>
</div>
<div id="jconsole" class="section">
<h3>Jconsole</h3>
<p>Jconsole also provides some basic information in heap utilization.</p>
<div class="highlight-text">
<div class="highlight">
<pre>#jps
16633 Jps
16624 Life

#jconsole 16624</pre>
</div>
</div>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/Screenshot-jconsole.png" alt="Connect jconsole to your application JVM to analyse garbage collection" /></p>
</div>
</div>
<div id="howto-tune-the-heap-utilization-of-the-jvm" class="section">
<h2>Howto tune the heap utilization of the JVM</h2>
<p>This section describes in detail how to analyse and tune a JVM. As I explained above a optimized configuration can neither be calculated nor guessed because the heap utilization depends on the application and its usage. We usually start with a suboptimal configuration provided by an experienced developer. On a test environment we put realistic load on the application and measure/ analyse the behaviour. From the analysis results we derive a optimized JVM configuration. This configuration will be tested and analysed again and so forth until we get satisfying outcome with our optimized JVM configuration.</p>
<p>In order to demonstrate the optimization of the heap utilization I wrote a small Java application that simulates the creation of two different lifeforms (grass and sheep) at given ratios. This is not a real life simulation. In fact you would be surprised how simple it is. The applications only purpose is to instantiate a lot of small objects with a little lifetime and some bigger objects that have a much higher lifespan. You can find the sample application here: <a class="reference external" href="http://bitbucket.org/markfink/testing-software/src/tip/gcview/tuning_sample/">http://bitbucket.org/markfink/testing-software/src/tip/gcview/tuning_sample/</a>.</p>
<div class="highlight-text">
<div class="highlight">
<pre>SCENARIO=grass-sheep
DAYS=5000            # number of days to simulate
SLEEPTIME=10         # slow down the simulation in ms

GRASS_GROWTHRATE=250 # amount of new entities every day
GRASS_MAXAGE=25      # entities die after they reach maxage
GRASS_SIZE=1000      # memory footprint for each entity

SHEEP_GROWTHRATE=5   # amount of new entities every day
SHEEP_MAXAGE=900     # entities die after they reach maxage
SHEEP_SIZE=10000     # memory footprint for each entity</pre>
</div>
</div>
<p>I visualized the behaviour of the simulation in the following diagram:</p>
<p><img style="width: 600px;" src="/wp-content/uploads/_images/grass-sheep-simulation.png" alt="Simulation of grass and sheep a defined growth rates" /></p>
<p>First approach towards running our sample application is without any configuration of the JVM. The execution failed with an OutOfMemoryError.</p>
<div class="highlight-text">
<div class="highlight">
<pre>Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at Lifeform.&lt;init&gt;(Life.java:86)
        at Life.&lt;init&gt;(Life.java:61)
        at Life.main(Life.java:13)</pre>
</div>
</div>
<p>If we analyse a little further we notice 49 full garbage collections within a few seconds. Note that there are no minor collections.</p>
<p><img style="width: 400px;" src="/wp-content/uploads/_images/grass-sheep-wo_conf.png" alt="OutOfMemoryError after 49 full garbage collections" /></p>
<p>We realize that the heap is way to small and decide to configure its size. The application now finishes without an error. Analysing the garbage collections we see that only one Full-Gc is executed. In the GC-diagram we are now able to identify single minor garbage collector runs and see how the Survivor spaces (From and To) are utilized.</p>
<p><img style="width: 400px;" src="/wp-content/uploads/_images/grass-sheep_1500MB.png" alt="All the full garbage collections are already gone" /></p>
<p>It will be tough to further optimize this heap configuration. In real world I would probably stick with this configuration but for the sake of demonstration I will try to further optimize the heap configuration.</p>
<p>I will start out with my standard heap configuration which turns out to reduce amount of minor-Gc runs by 80 percent. The time spent in GC is now down to 7 sec.</p>
<div class="highlight-text">
<div class="highlight">
<pre>-Xms1500m -Xmx1500m
-XX:NewSize=256m -XX:MaxNewSize=256m
-XX:PermSize=128m -XX:MaxPermSize=128m
-XX:SurvivorRatio=8</pre>
</div>
</div>
<p><img style="width: 400px;" src="/wp-content/uploads/_images/grass-sheep_1500MB_new750_sr8.png" alt="All the full garbage collections are already gone" /></p>
<p>Now I start optimizing the size of the survivor spaces. Please note that a bigger SurvivorRatio in the JVM configuration means smaller survivor spaces! I now set the SurvivorRatio to 12. All in all this results into a very tiny improvement. The only significant effect is that the Full-Gcs are now completely gone. The time spent in Gc is now down to 4.77 sec.</p>
<p><img style="width: 400px;" src="/wp-content/uploads/_images/grass-sheep_1500MB_new750_sr12.png" alt="All the full garbage collections are gone now" /></p>
<p>All of the above gc diagrams are created from the logfile with a Python script: <a class="reference external" href="http://bitbucket.org/markfink/testing-software/src/tip/gcview/">http://bitbucket.org/markfink/testing-software/src/tip/gcview/</a></p>
</div>
<div id="additional-information" class="section">
<h2>Additional Information</h2>
<p>[1] Whitepaper on memory management by Sun, <a class="reference external" href="http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf">http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf</a></p>
<p>[2] General information in Java performance, <a class="reference external" href="http://java.sun.com/docs/performance">http://java.sun.com/docs/performance</a></p>
<p>[3] Garbage Collection tuning guide, <a class="reference external" href="http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html">http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html</a></p>
<p>[4] Article on GC methods of the Java HotSpot VM, <a class="reference external" href="http://www.devx.com/Java/Article/21977/">http://www.devx.com/Java/Article/21977/</a></p>
<p>[5] Joseph D. Mocker’s collection of JVM Options, <a class="reference external" href="http://blogs.sun.com/roller/resources/watt/jvm-options-list.html">http://blogs.sun.com/roller/resources/watt/jvm-options-list.html</a></p>
<p>[6] Concurrent Mark and Sweep, <a class="reference external" href="http://research.sun.com/techrep/2000/smli_tr-2000-88.pdf">http://research.sun.com/techrep/2000/smli_tr-2000-88.pdf</a></p>
<p>[7] G1, <a class="reference external" href="http://research.sun.com/jtech/pubs/04-g1-paper-ismm.pdf">http://research.sun.com/jtech/pubs/04-g1-paper-ismm.pdf</a> and <a class="reference external" href="http://developers.sun.com/learning/javaoneonline/2008/pdf/TS-5419.pdf">http://developers.sun.com/learning/javaoneonline/2008/pdf/TS-5419.pdf</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/tools/gcview.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The eventoriented programming model</title>
		<link>http://www.testing-software.org/lang/the-eventoriented-programming-model.html</link>
		<comments>http://www.testing-software.org/lang/the-eventoriented-programming-model.html#comments</comments>
		<pubDate>Wed, 12 Jan 2011 19:58:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Lang]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://book.mark-fink.de/?p=49</guid>
		<description><![CDATA[Eventoriented Programming which is sometimes called “evented programming” is a programming model used as an alternative to programming with threads. Why does this matter I think it was around 1998 when we first learned that the clock rate could not be increased and we where about to seeing the end of Moore’s law that the [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div id="the-eventoriented-programming-model" class="section">
<p>Eventoriented Programming which is sometimes called “evented programming” is a programming model used as an alternative to programming with threads.</p>
<div id="why-does-this-matter" class="section">
<h2>Why does this matter</h2>
<p>I think it was around 1998 when we first learned that the clock rate could not be increased and we where about to seeing the end of Moore’s law that the number of transistors that compounds a CPU will double every two years. The CPU clockrate at this time was slightly below 1 GHz. A few month later clever scientists discovered a way around that barrier and Moore’s law applied again. The computer industry was saved. I believe I was not the only one who did not take it seriously when in 2005 they announced that they really can not increase the clockrate any further. I was like “yeah, you will discover it within no time”. Now it is crystal clear that the only way to increase the computing power of a CPU is to give it more cores. Energy consumption/ cooling constrains the clockrate and we know today that energy efficient computing requires clock rates to drop again to below 1 GHz.</p>
<p>Today having more than one core on the CPU is yesterdays news because everybody already has at least a dual core CPU in his or her PC. The hardware is available but parallel computing this is still the hardest challenge we are today facing in the computer industry. At the moment our machines have multiple cores but we are not able to put them to effective use. Not being able to increase computing power in the PC is a serious thread for the industry because nobody will replace one unless it breaks. Besides the economic aspects there are a lot of topics desperately waiting for more computing power like speech, image recognition, and advanced computer interfaces.</p>
</div>
<div id="what-to-do" class="section">
<h2>What to do</h2>
<p>What I think makes parallel computing really a hard problem is that there is currently and most likely there will be no general solution to the problem. Many computer scientists have spent their lives trying to find one. Among the most prominent is David Patterson who is Professor for Computer Architecture at Berkeley who worked on three separate projects on parallel computing. Many insights have been discovered but still the problem is far from being solved. On the other hand specific problems in this area have been addressed by today’s companies like Amazon, Facebook and Google. I think we can learn from them and look at the programming models used in their approaches.</p>
<p>I am convinced that there are at least to different kind of websites. There are sites that all people are using all the time like Amazon, Facebook and Google and on the other hand there are sites which are only use by some people some of the time. I am particularly interested in the later one so the rest of this piece is about the situation where you have less than 20.000 active connections at a time.</p>
</div>
<div id="programming-with-thread-vs-eventoriented-programming" class="section">
<h2>Programming with Thread vs. Eventoriented Programming</h2>
<p>One of the strange things in Software Engineering is that people have strong opinions and you can get easily into a situation one starts a fight over like for example Emacs vs. VI, Windows vs. Mac, Ruby vs. Python. Same here in programming models. I believe that most software engineers think that threads are the way to go when using multicore CPUs. One the other hand there are strong indications that this is not always true. John Ousterhout who has been so far to one of the most influential Computer Scientist for my own career gave in 1996 a talk on “Why Threads are a bad idea” at the USENIX conference. When I found his slides I smiled since at that very second it occurred to me that I am on the right track. The slides (<a class="reference external" href="http://home.pacbell.net/ouster/threads.pdf">http://home.pacbell.net/ouster/threads.pdf</a>) are freely available and you should definitely have a look. For this article I will only use his main argument that thread programming is extremely difficult to get right and a burden even for the best programmers.</p>
<p>Threads split the resources available to the operating system into pieces. Even if the resource consumption for a single thread is very small in total it sums up. For example a webserver which has 1GB available and splits it into 0.5 MB pieces for each thread is limited to 2.000 simultaneous requests. A recent example makes the issue very clear. The Apache webserver uses threads. Nginx is an Apache webserver clone where the threading mechanism was replaced by a event loop. It was successful and today Nginx by far outperforms Apache in terms of number of connections and memory utilization.</p>
<p>Eventoriented programming is a natural way and many programmers today prove to be comfortable using it.</p>
<p>Event oriented programming is often said to produce spaghetti code which is difficult to debug. I believe these are skill related issues and the event oriented programming model needs to be mastered like every other programming model. For example signal processing diagrams can help documenting programs following the event oriented model. Special debugging tools assign every callback a complete stack trace so that one can trace back the source of a given problem if he must.</p>
</div>
<div id="non-blocking-i-o" class="section">
<h2>Non-blocking I/O</h2>
<p>Non-blocking, or asynchronous I/O allows the computation to continue while the input/ output operation is running. So it is for example possible to have multiple database queries running at a time. Input and output operations on the network or file can be extremely slow compared to processing of data in memory. Most of I/O operations involve disc access in some form and spinning of discs is orders of magnitude slower than read/ write operations on a electronic circuit.</p>
<p>There are different forms of non-blocking I/O like polling, signals and callbacks.</p>
</div>
<div id="greenlet" class="section">
<h2>Greenlet</h2>
<p>Greenlets or eventlets are an abstraction on top of an event loop. When using greenlets one is programming in a blocking way and the framework is using the event loop and a scheduler under the hood. The programming model is more like threads but avoiding the resource consumption.</p>
</div>
<div id="callbacks" class="section">
<h2>Callbacks</h2>
<p>A callback is a function, that is passed as an argument to I/O operation. Once the I/O operation is completed the part of the program which deals with the results of this operation is invoked. It is possible to use anonymous callbacks but this is considered a bad practice since it makes programs difficult to read. Therefore named callbacks are to be preferred over anonymous callbacks.</p>
</div>
<div id="event-loop" class="section">
<h2>Event-loop</h2>
<p>The event loop, also called message dispatcher is a programming construct that waits for and dispatches events or messages in a program. It works by polling some internal or external “event provider”, which generally blocks until an event has arrived, and then calls the relevant event handler (“dispatches the event”).</p>
<p>Ted Faison’s book “Event-Based Programming: Taking Events to the Limit” proved very helpful to me in understanding the ins and outs of event oriented programming. The book follows a structured approach and is very well written.</p>
<p>According to Fairson the event programming model is by far the superior programming model especially for large software systems. Dependencies between software parts make large software systems complex and difficult to maintain. Dependencies have the biggest impact on software quality since the most complex parts also have the most dependencies. The event oriented programming model helps you gain better modularization so development, testing and maintenance of parts of the system is easier. Fairson makes a point that by following the event oriented programming model complexity grows linear with the size of the system while you will experience exponential grows when following other models. If this proves to be true this will be the biggest discovery in software engineering for the last decade.</p>
</div>
<div id="message-passing" class="section">
<h2>Message passing</h2>
<p>An event loop is one of the methods used for implementing inter-process communication. Message passing is currently used in many software systems, including operation system kernels.</p>
</div>
<div id="actor-model" class="section">
<h2>Actor model</h2>
<p>The actor model is a programming model that treats “actors” as the universal primitive. The actor model is an abstraction on the message passing model where in response to a message that it receives, an actor can make local decisions, create more actors, send more messages, and determine how to respond to the next message received.</p>
<p>In programming network servers we try to avoid abstractions and rip out many of the layers of the current software stack so we can get done more on a single machine (green computing).</p>
</div>
<div id="implementations" class="section">
<h2>Implementations</h2>
<p>As we have seen in this article the event loop is the superior programming model. Some remarkable implementations which support the event oriented programming model are available at the moment like Twisted and node.js.</p>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/lang/the-eventoriented-programming-model.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The eight queens puzzle</title>
		<link>http://www.testing-software.org/lang/eight-queens.html</link>
		<comments>http://www.testing-software.org/lang/eight-queens.html#comments</comments>
		<pubDate>Sun, 09 Jan 2011 11:09:01 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Lang]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mark-fink.de/book/?p=23</guid>
		<description><![CDATA[The eight queens puzzle is the problem of putting eight chess queens on an 8&#215;8 chessboard such that none of them is able to capture any other using the standard chess queen moves. The queens must be placed on the board in such a way that no two queens threaten each other. Thus, a solution [...]]]></description>
			<content:encoded><![CDATA[<p><span><strong><br />
</strong></span></p>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div id="the-eight-queens-puzzle" class="section">
<table class="docutils" border="1">
<colgroup>
<col width="23%"></col>
<col width="77%"></col>
</colgroup>
<tbody>
<tr>
<td><img style="width: 300px;" src="/wp-content/uploads/_images/eight_queens_sample.png" alt="Sample solution for the eight queens puzzle" /></td>
<td>The eight queens puzzle is the problem of putting eight chess queens on an 8&#215;8 chessboard such that none of them is able to capture any other using the standard chess queen moves. The queens must be placed on the board in such a way that no two queens threaten each other. Thus, a solution requires that no two queens share the same column, row, or diagonal. For the implementations below the generalized n-queens problem has been used.</td>
</tr>
</tbody>
</table>
<div id="implementations-using-functional-programming" class="section">
<h2>Implementations using functional programming</h2>
<p>I present the implementations of the n-queens puzzle in the order I have created them.</p>
<div id="common-lisp" class="section">
<h3>Common Lisp</h3>
<p>The Lisp solution is the first I present here since I started learning functional programming languages with Lisp. I did some research on algorithms to solve the 8-queens puzzle before I cam up with this attempt to implement one. For the algorithm it is clear that per column only one queen can be placed. Once understanding the symmetric properties of the chess board it became clear that the search space can be easily split in half using only the first half of the first column. Then only 46 of the 8-queens puzzle solutions are found. The remaining 46 solutions are found by just mirroring the board.</p>
<p>As you all know in functional programming a different way to decompose the problem is being used. In the beginning it was a hard for me to wrap my head around that. As always in similar situations I started drawing diagrams and once I understood that map, filter, and foldr are the basic building blocks I figured it out.</p>
<p><img style="width: 800px;" src="/wp-content/uploads/_images/map_filter_dfd.png" alt="Data flow graph for eight queens algorithm" /></p>
<p>I created the “multi” helper function to recurse 7 times over the map and filter. In retrospective the use of the compose macro might be more elegant.</p>
<div class="highlight-cl">
<pre>#!/usr/bin/env clisp

"The eight queens puzzle is the problem of putting eight chess queens
on an 8x8 chessboard such that none of them is able to capture any other
using the standard chess queen moves. The queens must be placed on the
board in such a way thot no two queens threaten each other. Thus, a
solution requires that no two queens share the same column, row, or
diagonal."

(defun filter (predicate sequence)
    "(filter #'oddp? (list 1 2 3 4 5)) -&gt; (1 3 5)"
    (remove-if-not predicate sequence) )

(defun enumerate-interval (low high)
    "create a list containing all numbers from low to high"
    (if (&gt; low high)
        ()
        (cons low (enumerate-interval (+ low 1) high))))

(defun reflect (l n)
    "reflect a given solution from the upper half of the board to the lower half."
    (if (null l)
        ()
        (cons (- n -1 (car l)) (reflect (cdr l) n) ) ))

(defun safe (l)
    "check if the last queen in the list is threatened by its successors"
    ; threads from same column are impossible in the choosen data structure
    (if (null (cdr l)) ; not threatened by itself
        T
        (if (= (car l) (car (last l))) ; check same row thread
            NIL
            ; check for diagonal thread
            (if (= (- (length l) 1) (abs (- (car l) (car (last l)))))
                NIL
                (safe (cdr l)) ))))

(defun queens (n)
    "list the solutions for the eight queens problem"
    ; only solve for half of the first column to reduce search space
    ; use reflect on the solutions later
    (mapcan
        (lambda (x)
            (if (and (oddp n) (= (car x) (ceiling (/ n 2))))
                (list x) ; selective reflection for odd numbers of n
                (list x (reflect x n)) ))
        (multi (- n 1)
            (add-next-col (enumerate-interval 1 (ceiling (/ n 2))) '())
            (enumerate-interval 1 n)
             )))

(defun add-next-col (vs l)
    "add the next column to l (all possible values in vs)"
    (if (null vs)
        NIL
        (cons (append l (list (car vs))) (add-next-col (cdr vs) l)) ))

(defun multi (r l intrval)
    "helper to map my operators multiple times"
    (if (= r 0)
        l
        (filter #'safe (mapcan
            (lambda (v) (add-next-col intrval v))
                (multi (- r 1) l intrval) )))) 

(defun print-usage-info ()
    "Print usage hints for this script."
    (format t "Usage: queens &lt;N&gt;~%")
    (format t "Description: Print the solutions to the queens puzzle.~%"))

(defun main (args)
    "Main function that analyses command-line arguments."
    (if (or (/= (length args) 1)
            (null (first args)))
        (print-usage-info)
        (let ((arg1 (parse-integer (first args) :junk-allowed t)))
    (if (integerp arg1)
        (format t "~A~%" (queens arg1))
        (print-usage-info)))))

(compile 'multi)
(compile 'add-next-col)
(compile 'queens)
(compile 'safe)
(compile 'reflect)
(compile 'enumerate-interval)

(main *args*)</pre>
</div>
</div>
<div id="haskell" class="section">
<h3>Haskell</h3>
<p>My first contact with Haskell was really an eye opener. When it comes to type systems I experience people to get very opinionated. Either you belong the the one (right) fraction or you will be considered an idiot! While learning Haskell I experienced the first time that this topic has shades of grey. In Haskell the types used in your function help you to argue (think) about your program. The nice side is that the type system does not get into your way. Haskell has type detection so you do not need to write all that type related boilerplate code you have in other strongly typed programming languages. And Haskell provides type classes so you do not need Generics. It is said that one of the most important goals in designing Haskell was to make statements very compact. For example Haskell uses the space character ” ” to notate application. This leads to very compact programs. My personal summary is that I am looking forward to see a lot more of Haskell in the future.</p>
<div class="highlight-haskell">
<div class="highlight">
<pre><span class="o">#!/</span><span class="n">usr</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">env</span> <span class="n">runhaskell</span>

<span class="c1">-- Haskell solution to the n-queens problem using list comprehension</span>

<span class="nf">boardSize</span> <span class="ow">=</span> <span class="mi">8</span>

<span class="nf">queens</span> <span class="ow">::</span> <span class="kt">Int</span> <span class="ow">-&gt;</span> <span class="p">[[</span><span class="kt">Int</span><span class="p">]]</span>
<span class="nf">queens</span> <span class="mi">0</span> <span class="ow">=</span> <span class="p">[</span><span class="kt">[]</span><span class="p">]</span>
<span class="nf">queens</span> <span class="n">n</span> <span class="ow">=</span> <span class="p">[</span> <span class="n">x</span> <span class="kt">:</span> <span class="n">y</span> <span class="o">|</span> <span class="n">y</span> <span class="ow">&lt;-</span> <span class="n">queens</span> <span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="n">x</span> <span class="ow">&lt;-</span> <span class="p">[</span><span class="mi">1</span><span class="o">..</span><span class="n">boardSize</span><span class="p">],</span> <span class="n">safe</span> <span class="n">x</span> <span class="n">y</span> <span class="mi">1</span><span class="p">]</span>
      <span class="kr">where</span>
         <span class="n">safe</span> <span class="n">x</span> <span class="kt">[]</span> <span class="n">n</span> <span class="ow">=</span> <span class="kt">True</span>
         <span class="n">safe</span> <span class="n">x</span> <span class="p">(</span><span class="n">c</span><span class="kt">:</span><span class="n">y</span><span class="p">)</span> <span class="n">n</span> <span class="ow">=</span> <span class="n">and</span> <span class="p">[</span> <span class="n">x</span> <span class="o">/=</span> <span class="n">c</span> <span class="p">,</span> <span class="n">x</span> <span class="o">/=</span> <span class="n">c</span> <span class="o">+</span> <span class="n">n</span> <span class="p">,</span> <span class="n">x</span> <span class="o">/=</span> <span class="n">c</span> <span class="o">-</span> <span class="n">n</span> <span class="p">,</span> <span class="n">safe</span> <span class="n">x</span> <span class="n">y</span> <span class="p">(</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">)]</span>

<span class="c1">--main  = print $ queens 8</span>
<span class="nf">main</span>  <span class="ow">=</span> <span class="n">print</span> <span class="o">$</span> <span class="n">length</span> <span class="p">(</span><span class="n">queens</span> <span class="mi">8</span><span class="p">)</span></pre>
</div>
</div>
</div>
<div id="erlang" class="section">
<h3>Erlang</h3>
<p>Having deep roots in Prolog Erlang has no static typing. The current hype concerning Erlang is about its strong support for parallel computing. I did not use this feature in the following solution. As you can see the Erlang and Haskell solutions are very similar and it is easy to transform one into the other.</p>
<div class="highlight-erlang">
<pre>#!/usr/bin/env escript
-export([main/1]).

queens(0) -&gt; [[]];
queens(N) -&gt; [ [X|Y] || Y&lt;-queens(N-1), X&lt;-[1,2,3,4,5,6,7,8], safe(X, Y, 1)].

safe(X, [], N) -&gt; true;
safe(X, [C|Y], N) -&gt; (X /= C) and (X /= C + N) and (X /= C - N)
    and safe(X, Y, (N+1)).

main([X]) -&gt;
    N = list_to_integer(X),
    Q = queens(N),
    % io:format("~w~n",[Q]).
    io:format("~w~n",[length(Q)]).</pre>
</div>
</div>
<div id="python" class="section">
<h3>Python</h3>
<p>Python has elegant support for List Comprehensions as well. Consequently there is not a huge difference to the Haskell and Erlang solutions besides that the Python solution it is a little bit more verbose.</p>
<div class="highlight-python">
<div class="highlight">
<pre><span class="c">#!/usr/bin/env python</span>

<span class="sd">"""The eight queens puzzle is the problem of putting eight chess queens </span>
<span class="sd">on an 8x8 chessboard such that none of them is able to capture any other </span>
<span class="sd">using the standard chess queen moves. The queens must be placed on the </span>
<span class="sd">board in such a way thot no two queens threaten each other. Thus, a </span>
<span class="sd">solution requires that no two queens share the same column, row, or </span>
<span class="sd">diagonal."""</span>

<span class="k">def</span> <span class="nf">queens</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="sd">"""Compute the solutions for the n-queens puzzle."""</span>
    <span class="n">board_size</span> <span class="o">=</span> <span class="n">n</span>
    <span class="k">def</span> <span class="nf">queens_intern</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">n</span><span class="o">==</span><span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">[[]]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">[</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+</span><span class="n">y</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">queens_intern</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">board_size</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="n">safe</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="mi">1</span><span class="p">)]</span>

    <span class="k">return</span> <span class="n">queens_intern</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">safe</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
    <span class="sd">"""Is the queen x threatened by the others (y)?"""</span>
    <span class="k">if</span> <span class="n">y</span><span class="o">==</span><span class="p">[]:</span>
        <span class="k">return</span> <span class="bp">True</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">((</span><span class="n">x</span> <span class="o">!=</span> <span class="n">y</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="ow">and</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">n</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">n</span><span class="p">)</span>
            <span class="ow">and</span> <span class="n">safe</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">[</span><span class="mi">1</span><span class="p">:],</span> <span class="p">(</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">)))</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
    <span class="k">print</span> <span class="nb">len</span><span class="p">(</span><span class="n">queens</span><span class="p">(</span><span class="mi">12</span><span class="p">))</span></pre>
</div>
</div>
</div>
<div id="javascript" class="section">
<h3>Javascript</h3>
<p>Javascript implementations which follow the Ecma 262 Standard do not support List Comprehensions. For example the V8 Javascript engine follows this 1999 standard very closely. But there is considerable hope that with the Harmony Project and the 6th edition of the standard the goodness implemented in Javascript 1.7 like List Comprehensions will be taken up.</p>
<p>Haskell has a strong support for mathematical reasoning about programs. So a side-effect of learning Haskell was that I also learned how to transform one expression into another. For example a list comprehension can be expressed as a composition of map and filter.</p>
<div class="math">
<p><img src="/wp-content/uploads/_images/math/c10acf65b22893afc5a68611a6bfc7002e2b70dc.png" alt="[ x * x | x \leftarrow [1..5], odd \: x] \equiv (map \: square \: \circ \: filter \: odd)[1..5]" /></p>
</div>
<p>Above an example for a equivalence transform of a list comprehension into a composition of map and filter. The function composed of map and filter is much less readable than the nested list comprehension.<br />
The list comprehension is constructed in one pass whereas the application of the map and filter function takes two passes. However if one does the composition in the wrong order he is in deep trouble since he gets a program which still computes the correct solution but this tiny little difference has a huge impact on performance. In the 8-queens solution the queens_intern function is called nine times. If the order is wrong it is called 20 million times which results into a factor 1000x impact on execution time. I think these are strong arguments in favour of using list comprehensions.</p>
<div class="highlight-javascript">
<div class="highlight">
<pre><span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

<span class="kd">function</span> <span class="nx">queens</span><span class="p">(</span><span class="nx">q</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">board_size</span> <span class="o">=</span> <span class="nx">q</span><span class="p">;</span>
    <span class="kd">function</span> <span class="nx">queens_intern</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">count</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">n</span><span class="o">==</span><span class="mi">0</span><span class="p">){</span>
            <span class="k">return</span> <span class="p">[[]];</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="c1">// Javascript normally has no list comprehension so I had to </span>
            <span class="c1">// transform it using map/ filter and consequently lost some readability</span>
            <span class="c1">// [ [x]+y for y in queens(n-1) </span>
            <span class="c1">//        for x in xrange(1, board_size+1) if safe(x, y, 1)]    (Python)</span>
            <span class="c1">// the following commented out code invokes queens() 19173961 times</span>
            <span class="c1">// real	1m27.636s, user	1m27.933s, sys	0m0.296s</span>

    <span class="cm">/*        return _.reduce(_.map(_.range(1,9), </span>
<span class="cm">                                  function(x) {</span>
<span class="cm">                                    return _.filter(_.map(queens(n-1), </span>
<span class="cm">                                                          function(y) {return [x].concat(y);} ), </span>
<span class="cm">                                                    function(f) {return safe(f[0], _.rest(f), 1);} );}</span>
<span class="cm">                                  ), </span>
<span class="cm">                            function(c,d) {return c.concat(d);}</span>
<span class="cm">                            ); */</span>
            <span class="k">return</span> <span class="nx">_</span><span class="p">.</span><span class="nx">reduce</span><span class="p">(</span><span class="nx">_</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">queens_intern</span><span class="p">(</span><span class="nx">n</span><span class="o">-</span><span class="mi">1</span><span class="p">),</span>
                                  <span class="kd">function</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
                                    <span class="k">return</span> <span class="nx">_</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">_</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">_</span><span class="p">.</span><span class="nx">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nx">board_size</span><span class="o">+</span><span class="mi">1</span><span class="p">),</span>
                                                          <span class="kd">function</span><span class="p">(</span><span class="nx">y</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="p">[</span><span class="nx">y</span><span class="p">].</span><span class="nx">concat</span><span class="p">(</span><span class="nx">x</span><span class="p">);}</span> <span class="p">),</span>
                                                    <span class="kd">function</span><span class="p">(</span><span class="nx">f</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="nx">safe</span><span class="p">(</span><span class="nx">f</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">_</span><span class="p">.</span><span class="nx">rest</span><span class="p">(</span><span class="nx">f</span><span class="p">),</span> <span class="mi">1</span><span class="p">);}</span> <span class="p">);}</span>
                                  <span class="p">),</span>
                            <span class="kd">function</span><span class="p">(</span><span class="nx">c</span><span class="p">,</span><span class="nx">d</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="nx">c</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">d</span><span class="p">);}</span>
                            <span class="p">);</span>
        <span class="p">}</span>
    <span class="p">};</span>
    <span class="k">return</span> <span class="nx">queens_intern</span><span class="p">(</span><span class="nx">q</span><span class="p">);</span>
<span class="p">};</span>

<span class="kd">function</span> <span class="nx">safe</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">y</span><span class="o">==</span><span class="kc">undefined</span> <span class="o">||</span> <span class="nx">y</span><span class="p">.</span><span class="nx">length</span><span class="o">==</span><span class="mi">0</span><span class="p">){</span>
        <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span><span class="p">{</span>
        <span class="k">return</span> <span class="p">((</span><span class="nx">x</span> <span class="o">!=</span> <span class="nx">y</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">x</span> <span class="o">!=</span> <span class="nx">y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="nx">n</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="nx">x</span> <span class="o">!=</span> <span class="nx">y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="nx">n</span><span class="p">)</span>
            <span class="o">&amp;&amp;</span> <span class="nx">safe</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">_</span><span class="p">.</span><span class="nx">rest</span><span class="p">(</span><span class="nx">y</span><span class="p">),</span> <span class="p">(</span><span class="nx">n</span><span class="o">+</span><span class="mi">1</span><span class="p">)));</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kd">var</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">queens</span><span class="p">(</span><span class="mi">8</span><span class="p">);</span>
<span class="c1">//_.each(res, function(x) {print(x);});</span>
<span class="nx">print</span><span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span>
<span class="nx">print</span><span class="p">(</span><span class="nx">count</span><span class="p">);</span></pre>
</div>
</div>
<p>The underscore.js library provides the basic building blocks like map, filter, reduce which I needed. I downloaded the V8 Javascript engine and compiled it with the “sample=shell” option. Now I can run it on my machine “time shell underscore.js queens_map_filter.js”.</p>
</div>
</div>
<div id="finally-execution-times" class="section">
<h2>Finally, execution times</h2>
<p>The solutions for the n-queens puzzle discussed above have not been optimized for performance. Focus of the solutions is on readability and experimentation with functional programming concepts. I currently work as a performance engineer and therefore I need to get some insights on execution time considerations, too.</p>
<p><strong>Before you draw any conclusions based on the numbers below please be aware that this is not a comprehensive benchmark for real applications!</strong> If you think the problem is not a realistic one your applications are structured differently. Then I must say that I choose the problem purposefully since it resembles the kind of problem I am tying to solve and why I turned to functional programming in the first place. The eight queens problem is sufficient for me to get a feeling for the kind of work I am planning to do.</p>
<p>One can always argue that the comparison is not fair because of XYZ. I hope I did not hurt anybody’s feelings. If you think there is something wrong with a solution or the benchmark please let me know.<br />
Since I tried to be fair I also included measurements of the compiled versions of the Erlang and Haskell solutions as well.</p>
<table class="docutils" border="1">
<colgroup>
<col width="10%"></col>
<col width="17%"></col>
<col width="27%"></col>
<col width="27%"></col>
<col width="19%"></col>
</colgroup>
<tbody>
<tr>
<td>n-queens</td>
<td>Common Lisp</td>
<td>eight_queens_sussman.lisp</td>
<td>eight_queens.lisp</td>
<td></td>
</tr>
<tr>
<td>8</td>
<td></td>
<td>0m1.024s</td>
<td>0m0.052s</td>
<td></td>
</tr>
<tr>
<td>12</td>
<td></td>
<td>( stack overflow)</td>
<td><strong>0m26.466s</strong></td>
<td></td>
</tr>
<tr>
<td></td>
<td>Haskell</td>
<td>queens_list_compr.hs</td>
<td></td>
<td>compiled version</td>
</tr>
<tr>
<td>8</td>
<td></td>
<td>0m0.488s</td>
<td></td>
<td>0m2.668s</td>
</tr>
<tr>
<td>12</td>
<td></td>
<td>2m34.238s</td>
<td></td>
<td><strong>0m12.353s</strong></td>
</tr>
<tr>
<td></td>
<td>Erlang</td>
<td>queens_list_compr.erl</td>
<td>queens.erl</td>
<td>compiled version</td>
</tr>
<tr>
<td>8</td>
<td></td>
<td>0m4.460s</td>
<td>0m12.213s</td>
<td>0m0.240s</td>
</tr>
<tr>
<td>12</td>
<td></td>
<td>72m57.726s</td>
<td>251m56.077s</td>
<td>0m58.552s</td>
</tr>
<tr>
<td></td>
<td>Python</td>
<td>queens_list_compr.py</td>
<td>queens_map_filter.py</td>
<td>queens_conjoin.py</td>
</tr>
<tr>
<td>8</td>
<td></td>
<td>0m0.080s</td>
<td>0m0.116s</td>
<td>0m0.032s</td>
</tr>
<tr>
<td>12</td>
<td></td>
<td>0m56.384s</td>
<td>65m1.556s</td>
<td><strong>0m10.021s</strong></td>
</tr>
<tr>
<td></td>
<td>Javascript (V8)</td>
<td></td>
<td>queens_map_filter.js</td>
<td>using Rhino</td>
</tr>
<tr>
<td>8</td>
<td></td>
<td></td>
<td>0m0.100s</td>
<td>0m5.020s</td>
</tr>
<tr>
<td>12</td>
<td></td>
<td></td>
<td>13m19.194s</td>
<td>11m9.562s</td>
</tr>
</tbody>
</table>
<p>I must say the results are a little different to what I had expected. For example I did not expect the Common Lisp solution to be so fast. On the other hand I am really disappointed about the performance of Erlang. Nobody promised something like that to me but there is so much hype lately about Erlang’s suitability for parallel computing so I assumed that it would be fast as well. I am also a bit disappointed by the V8 Javascript implementation. From the projects benchmarks I concluded that the n-queens solver would be much faster. I hope that the V8 team will take up list comprehensions soon similar to what Mozilla did in 2006. Also I did not expect this outcome I must say for me Python is the true winner. Especially since it is so often said to be slow.</p>
<p>I know that Javascript 1.7 (this is the Mozilla version) contains array comprehensions and I wanted to give it a try using Spidermonkey. So I tried to use Spidermonkey smjs on Ubuntu 10.10 but unfortunately the Spidermonkey-bin package is gone and I could not find a workaround. I will redo the Javascript test as soon as a suitable workaround is found to get smjs running on Ubuntu again.</p>
</div>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.testing-software.org/lang/eight-queens.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

