Coding Using Conventions and Not Configurations

an article added by: Sonja Lande at 05312007


In: Categories » Computers and technology » AJAX » Coding Using Conventions and Not Configurations

Coding Using Conventions and Not Configurations

Problem You want to make your JavaScript constructs more efficient by applying the Rails “convention over configuration” principle to them. Theory You may already be familiar with the programming platform Ruby on Rails, which is used to build Web applications. The focus of this recipe is not Ruby on Rails, but one aspect of Ruby on Rails namely, convention over configuration (see http://en.wikipedia.org/wiki/ Ruby_on_Rails for more on this). Imagine writing tests and realizing that you use a same set of instructions over and over again. When you convert the code from the repeated code into generic code, you are creating a framework. The framework can be created in one of two ways. The first way is to create infrastructure and wire it together, and the second is to make assumptions about your code. Consider the following JavaScript JsUnit test:

    var testsToRun = {
    // Start JavaScript code for test cases here
    testPlainVanilla : function() {
    // Some code
    testManager.success();
    }
    // End JavaScript code for test cases
    };
 testManager.setTestCases( testsToRun);

The details of what the variables and classes do are not relevant. What is relevant is how they are wired together. The testsToRun variable contains a number of methods that are used to execute particular tests. When each test has completed successfully, the testManager.success method is called. The testsToRun variable is not associated with any other method, data member, or function simply put, testsToRun is hanging like a flag in the wind. Of course, we don’t want testsToRun to hang in the wind; we want the tests to be executed.

The tests are executed by the testManager variable, and testManager has no knowledge of testsToRun. The challenge is figure out how to make testManager aware of testsToRun and, once it’s aware, to execute the contained tests. The wiring of testManager to testsToRun can be a convention or a configuration. In the preceding example, the solution used to make testManager aware of testsToRun is configuration. In classical programming terms, you can think of configuration as being a file on a hard disk with pieces of text that are parsed by an algorithm. That process is a configuration, but it’s just one type of configuration. Another type known as programmatic configuration involves the source code telling the classes how everything is wired together. I am not going to cover the advantages and disadvantages of the different configuration types suffice it to say that configuration is used to wire together unknown implementations to create a working system. Configuration is often used because it is an easy way to create a working system. Configuration does not require a deduction algorithm; rather, it needs just an algorithm that can parse a configuration file or a programmer who can wire implementations together. In a nutshell, configuration requires the programmer or administrator to do some of the heavy lifting of figuring out what piece is wired to the other piece. If something doesn’t work, then the system can say, “Oops, that doesn’t work.

Try again.” Convention can seem to be a more complicated way to create a working system that’s more art than science. As an analogy, in the movie I, Robot, the actor Will Smith plays a policeman, Del Spooner, who doesn’t like robots. During the robot interrogation scene, Spooner winks at another policeman leaving the questioning room. The robot asks Will what the wink meant, and Spooner explains that the wink is something that a human knows. At a later point in the movie, the robot uses a wink to send amessage to Spooner. Spooner is surprised, but he knows what it means and acts appropriately. So how does the wink relate to convention? To someone who knows what the wink is, it is a single simple piece of information that has many implications. To someone who doesn’t know what the wink is, it is dismissed as irrelevant.

A person who dismisses the wink is missing a piece of vital information and could be considered out of the loop of knowledge. The wink represents a complicated piece of information that requires a context to completely understand. One critique of Ruby on Rails is that it’s more art than science, and thus not logical, since it uses convention in other words, it’s like the wink, and if you don’t have the context to understand it, it doesn’t make sense. I would like to counter that configuration uses convention, and thus is a convention. In the simplest case, configuration is self-explanatory, but in the more complex case, a configuration file is a convention all on its own. To understand the configuration, you need to understand the convention of the configuration, which begs the question, why use a configuration? The answer is that sometimes a configuration is the appropriate solution because it offers flexibility; with convention, you do things according to a predetermined overall scheme. The reason configuration has become a convention is that in many cases, developers think they need to use configuration to gain flexibility, when in fact convention would have been good enough. Implementing convention does require using reflection, because to make a decision based on convention, you need to know the current context. The big advantage of using convention is that you don’t need to maintain configuration whenever changes occur a convention automatically picks up the latest changes. The following are some scenarios in which you would use convention over configuration:

• When you need to constantly update and manage cross-reference information (e.g., database columns that are mapped to class data members).

• When your configuration is only of importance to a developer and not an administrator. For example, you would expect an administrator to want to configure which database your application will connect to. But you would not expect your administrator to configure which model belongs to which view and which controller in aModel-View-Controller (MVC) architecture.

• When you can use reflection and call methods anonymously, without knowing the type information. It is possible to implement conventions using programming languages such as C# and Java, as they support reflection, but the ability to call methods anonymously is much more complicated. Using dynamic languages such as JavaScript and Ruby, it is very easy to call methods or properties on types.

• When you need to provide your users (and yourself) with hints if something goes wrong. When you use conventions, it is very important to clearly indicate what is wrong when something does not work. Ruby on Rails does a very good job of providing hints about what to do next when something goes wrong. This feature is important because writing code for a system that uses convention only works if you know the convention. Solution For this recipe, we’ll convert the unit-testing framework described previously into a completely convention-based system. Then when writing unit tests, our only task will be to implement a series of tests in a structure, and the unit-testing framework will do the rest. For illustration purposes, let’s look at the template of the unit test again and identify the pieces that need to be converted from a configuration approach to a convention approach.

    Source: /jaxson/trunk/website/ROOT/scripts/templates/testcontract.html
 <html>
 <head>
 <title>Contract Test Page</title>
 <script language="JavaScript"  src="/scripts/common.js"></script>
 <script language="JavaScript"  src="/scripts/Synchronous.js"></script>
 <script language="JavaScript"  src="/scripts/commontest.js"></script>
 <script language="javascript"  src="/scripts/jsunit/jsUnitCore.js"></script>
 </head>
 <body>
 <script language="javascript">
 // Setup the output generator
 setJsUnitTracer(  new jsUnitTraceGenerator( "traceoutput"));
 // Start of defined contract URL's
 // Potentially define a URL as
 // var baseURL = "/my/url";
 // End of defined contract URL's
 var testsToRun = {
 // Start JavaScript code for test cases here
 testPrototype : function() {
 // Synchronous functions identically to  Asynchronous
 // but Synchronous waits for the request to  complete
 // Good for testing, but bad for production as  the browser hangs
 var request = new  Synchronous();
 request.complete = function( statusCode,  statusText,➥
 responseText, responseXML){
 // Do something with the result
 // Indicate that you are done, and define the  output element
 testManager.success(  "statusPrototype");
 }
 // Do something with the request
 }
 // End JavaScript code for test cases
 };
 testManager.setTestCases(  testsToRun);
 </script>
 <table>
 <tr>
 <td><h2>Available  Tests</h2></td>
 <td></td>
 </tr>
 <tr>
 <td>
 <input  onclick="testManager.runAll()" type="button"  value="Run All Tests" />
 </td>
 <td></td>
 </tr>
 <tr>
 <td>Test</td>
 <td>Status</td>
 </tr>
 <!-- Insert GUI for test cases here -->
 <tr>
 <td>
 <input  onclick="testManager.testPrototype()" type="button"value="Test  Prototype" />
 </td>
 <td  id="statusPrototype">Not run</td>
 </tr>
 <!-- End test cases here -->
 </table>
 <hr />
 <table border="1">
 <tr>
 <td><h2>Trace  output</h2></td>
 </tr>
 <tr>
 <td  id="traceoutput"></td>
 </tr>
 </table>
 </body>
 </html>

The bold lines in the preceding example represent configuration-based code that will be converted into convention-based code. When converting from configuration-based code to convention-based code, you can apply one of two approaches. The first approach is to rewrite the classes used by the unit-testing framework so that they become completely convention based. The advantage to this approach is that the classes are lean and solve the task. The second approach is to keep the configuration functionality, and write a layer on top that implements the convention functionality. The advantage of this approach is that multiple convention solutions can be applied, but the disadvantage is an additional overhead. We’ll implement the second approach here, and keep both the configuration and convention layer as lean as possible. Ideally, the configuration layer should contain only the functionality needed by the convention. Additional functionality in the configuration adds unnecessary baggage. The base unit-testing file when converted into a convention file is similar to the following.

    Source: /website/ROOT/ajaxrecipes/javascript/conventionconfiguration.html
 <html>
 <head>
 <title>Convention over  Configuration</title>
 <script language="JavaScript"  src="/scripts/jaxson/common.js"></script>
 <script language="JavaScript"  src="/scripts/jaxson/commontest.js"></script>
 <script language="javascript"  src="/scripts/jsunit/jsUnitCore.js"></script>
 </head>
 <body>
 <script language="javascript">
 // Setup the output generator
 //  *******************************************************
 function AddTwoNumbers(num1, num2) {
 return num1 + num2;
 }
 //  *******************************************************
 var testsToRun = {
 // Start JavaScript code for test cases here
 plain_vanilla : function() {
 assertEquals(4, AddTwoNumbers(2, 2));
 },
 failed_test : function() {
 testManager.failed();
 },
 exception_failed : function() {
 obj.notexistent();
 }
 // End JavaScript code for test cases
 };
 </script>
 <div  id="unittestoutput"></div>
 <script  language="JavaScript"  src="/scripts/jaxson/conventiontest.js"></script>
 </body>
 </html>

The modified code includes three tests, but notice the drastic reduction in code in this example. Also notice that certain code constructs are implied and do not need to be written explicitly (e.g., testManager.success). From a user perspective, the reduction and simplification of the code is a good thing, but in fact there are many hidden aspects that you’ll need to be aware of, because when something goes wrong, you need to know why it happened. The details of how this code was implemented are not covered in the recipe they are discussed throughout this article but the following general concepts are implemented:

• The HTML code that contained the buttons is dynamically generated by a strategically placed include file (conventiontest.js). The file is placed where it is so that the variables will already have been declared and available for initialization.

• The testsToRun variable is an implied-to-exist variable and is inspected for available tests. For each test method, a button is generated, where the name of the button is the name of the test method.

• Each method uses a proxy to encapsulate and automatically handle errors or successful tests appropriately. When creating your own convention-based code, keep in mind the following points:

Initialization: In configuration-based code, you are responsible for initialization of the variables and objects; in convention-based code, the code is mostly responsible for initializing itself. It’s like starting a car: you expect the car to feed fuel to the engine, and you just want to turn the key and be able to drive. The problem with initialization is that you don’t always know the context.

• You have two ways to initialize. The first is to initialize and configure when the JavaScript is loaded, as illustrated by the XMLHttpRequest factory in Recipe 2-4. The second is to initialize when the first action takes place. In the second scenario, a flag indicating the status of initialization is set to false when the JavaScript is loaded. Then as the first action takes place, the initialization happens.

Error checking: Convention systems expect certain variables or types declared, and if they are not declared, problems arise. A convention system must have error routines that catch every error and explain in detail what went wrong. Many developers might think that a convention system should be adaptable and work around not entirely correct code. This is a big misconception providing workarounds makes for a sloppy developer. Convention-based code requires good coding practices, so that everybody codes to the same convention. Don’t take shortcuts.

Naming consistency: Whenever you label identifiers, you need to be consistent. The name of the identifier needs to be as obvious as possible. Don’t try to be clever, slick, or cryptic. Ruby on Rails is successful for many reasons, one of which is that the naming conventions are obvious, consistent, and intuitive.

legal notice

Our website is not responsible for the information contained by this article. Web-articles is a free articles resource.
Suggestion: If you need fresh, daily updated content for your website, feel free to use our service. Click here for more information.

Useful tools and features

Link to this article from your page    Send this article to you or to a friend
If you like this article (tutorial), please link to it from your web page using the information above.

related articles

1. Understanding the Definition and Philosophy of REST
Understanding the Definition and Philosophy of REST REST is a controversial topic among Web service enthusiasts, because it’s considered to stand for the opposite of what Web services and SOA are trying to achieve. The problem with this thinking is that REST is not in contradiction with the abstract definition of SOA and Web services. REST is in contradiction with technologies such as SOAP, WSDL, and WS-* specifications. The following offers a quick definition of REST:...

2. The Easiest Way to Get Started with Ajax and REST
The Easiest Way to Get Started with Ajax and REST Problem You want to know the best way to get started with writing Ajax and REST. Solution When developing an Ajax and REST application, you must decide on the tools and frameworks you’ll use. The choice is simple: Use whatever you’re using today, and write some Ajax applications. You don’t need to change the tools you’re using today. Whether you’re using ASP.NET, JavaServer Pages (JSP), PHP, Ruby, or Python, you...

3. Testing a Dynamic Contract with Ajax
Coding the Contract Using Test-Driven Development Techniques Coding the contract using agile and test-driven development techniques requires writing a number of tests and implementing aMock URL layer. Problem You want to code the contract using these development techniques. Solution To demonstrate, let’s define a use case, implement the use case as a contract, write a test case(s) to implement the contract, implement the contract in the Mock URL, and finally...

4. Testing the Client Side Logic
Problem You want to effectively test your application’s client-side logic. Theory Testing GUI code tends not to be a productive task because of the complications that arise. The main complication is how to test the correctness of a user interface. Imagine a situation where clicking a button causes a table to be filled with data. Now imagine that when a check box is checked and the button is clicked again, a different table is filled with content. The fact that clicking the same button results in two ...

5. Understanding JavaScript and Types
Understanding JavaScript and Types Problem You want to work around the fact that JavaScript does not have types declared for its variables. Theory JavaScript code does not have any variables with a declared type. The lack of typed variables is apparent when you declare functions. That said, not having typed variable declarations does not mean JavaScript has no types or no type safety. Let’s start out with the simple declaration of a function, as illustrated by the following ex...

6. Advantage of parameterless functions in JavaScript
Using Parameterless Functions Problem You want to take advantage of parameterless functions in JavaScript. Theory JavaScript functions for the most part have parameters. You may think that the previous sentence states the obvious after all, without parameters, what data could be passed to a function? JavaScript has the ability to declare functions that have no parameters, even though the caller of the function has passed parameters to the function. For example, let’s look at...

7. JavaScripot Functions
Treating Functions Like Objects Problem You want to take advantage of the fact that functions are objects (remember, everything is an object in JavaScript). Theory Many people think that a function is some keyword used in JavaScript. A function is also an object that can be manipulated. Knowing that a function is an object makes it very interesting from the perspective of writing JavaScript code, because the code can treat the function like another other object. This mean...

8. Implementing an Error and Exception Handling Strategy
Implementing an Error and Exception Handling Strategy Problem You want to implement a clean error and exception handling strategy in your applications, to make them run more smoothly. Theory Of course, you might argue that one error is a dialog box and the other is generated in the JavaScript console. The fact that one browser uses a dialog box to show an error and the other does not is a browser issue, not an error issue. A concise way of classifying the two errors is to ...