<?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>Danilo Gurovich &#187; Enterprise Development</title>
	<atom:link href="http://gurovich.com/site/category/enterprise-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://gurovich.com/site</link>
	<description>Strategic eCommerce Technology and Architecture</description>
	<lastBuildDate>Mon, 25 Sep 2023 14:32:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>The Dinosaur Feed Pen</title>
		<link>http://gurovich.com/site/2011/07/19/the-dinosaur-feed-pen/</link>
		<comments>http://gurovich.com/site/2011/07/19/the-dinosaur-feed-pen/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 22:50:31 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Dev process]]></category>
		<category><![CDATA[Enterprise Development]]></category>
		<category><![CDATA[development environment]]></category>
		<category><![CDATA[dinosaur feed pen]]></category>
		<category><![CDATA[facebook environment]]></category>
		<category><![CDATA[google environment]]></category>
		<category><![CDATA[hate cubicles]]></category>
		<category><![CDATA[innovative office]]></category>
		<category><![CDATA[no cubicles]]></category>

		<guid isPermaLink="false">http://gurovich.com/site/?p=1340</guid>
		<description><![CDATA[I&#8217;ve just spent more than a year working in a development group. We sit around a big oval table and work. We meet there, write code there, prepare presentations there, eat lunch there. There&#8217;s no &#8220;head&#8221; of the table; no &#8220;kids table&#8221;. It&#8217;s an island, and everyone&#8217;s on it. We&#8217;re all equals, peers and have [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;">I&#8217;ve just spent more than a year working in a development group. We sit around a big oval table and work. We meet there, write code there, prepare presentations there, eat lunch there. There&#8217;s no &#8220;head&#8221; of the table; no &#8220;kids table&#8221;. It&#8217;s an island, and everyone&#8217;s on it. We&#8217;re all equals, peers and have as much to learn as we have to teach. There&#8217;s no politics. No heroes. No wallflowers. There&#8217;s just &#8220;the work&#8221;. Oh, and it&#8217;s just plain fun. Every freekin&#8217; day.</p>
<p style="text-align: left;"><a href="http://gurovich.com/site/wp-content/uploads/2011/07/tron-28-office-cubicles.jpg"><img class="size-full wp-image-1345 alignnone" title="tron-28-office-cubicles" src="http://gurovich.com/site/wp-content/uploads/2011/07/tron-28-office-cubicles.jpg" alt="" width="475" height="220" /></a></p>
<p>Cubicles are the worst invention in the history of business. I&#8217;m still trying to think about how/why somebody thought this was a good idea. The only thing I can come up with is a secret society of Janitors, maintenance people and office furniture salespersons have formed some kind of plutocracy that actually control how we work.</p>
<p>Cubes make sense if you just take them in a two-dimensional plane. They are configurable in thousands of ways. You get a desk. You get a chair. You get some drawers and overhead storage. It locks. When you&#8217;re not there, you can put everything away and it&#8217;s all pretty and clean. And beige, or gray, or some kind of color that a tribe in Peru may call &#8220;Llama Vomit&#8221;. They were made for another place and time.</p>
<p>I have sat in cubes for the last 15 years except on a few wonderful occasions. They all pretty much looked the same. High walls that caused you to &#8220;gopher&#8221; when any kind of sound or personal communication was needed. Cramped and created so you face away from your door, so collaborating with anyone or even coming into another&#8217;s cube is an unexpected interruption at best, downright startling at worst. If you&#8217;ve been sentenced to a cube, how many of you have &#8220;rear view mirrors&#8221; or your monitor is positioned in such a way as you can see shadows behind you?</p>
<p>Of course, if you&#8217;re some kind of &#8220;middle manager&#8221;, you might have one of the &#8220;bigger&#8221; cubes that have a &#8220;desk&#8221; that protrudes through the middle and allows others to sit at it facing you. You get to be the &#8220;boss&#8221;, because it&#8217;s &#8220;your&#8221; cube, &#8220;your&#8221; desk, and others are there to seek your patronage. Now think about it. You&#8217;re really not going to do any &#8220;serious&#8221; business and your superiors sitting in their offices are showing that they have given you no &#8220;real&#8221; power. If you raise your voice above a whisper, you&#8217;ll be heard by persons 20 feet away. Nothing important or sensitive can be discussed there, so a &#8220;meeting room&#8221; must be booked or squatted in. Worthless.</p>
<p>Cubes have fabric walls and fixed furniture. Want to do some design? Where do you put the whiteboards? How do you collaborate? There&#8217;s drawers everywhere, and cubes are designed to stick your monitor in the corner (designed when monitors were 17&#8243; wide and 20&#8243; deep, too) and anyone working with you at your desk will be constantly banging their knees in the crappy &#8220;guest&#8221; chair that he&#8217;s borrowed from the cube around the wall.</p>
<p>Then there&#8217;s the cube farm. Row upon row of cubes in a giant room. 6 feet high, 50-75 feet wide and 150 feet long. The rows have hastily-printed pieces of paper in fourteen-point type that tells you who &#8220;lives&#8221; down that row. It&#8217;s like some kind of weird Stalinist housing project gone horribly wrong.</p>
<p>But it&#8217;s really easy to keep &#8220;looking&#8221; clean (whether it&#8217;s actually &#8220;sanitary&#8221; is debatable). I&#8217;t easy for your boss to walk down the row and quickly see who&#8217;s there and if everyone&#8217;s working. Everyone has their place. Everyone knows their job. Everyone is pounding away, waiting for 5 o&#8217;clock or a meeting to come up on their dilapidated, ancient version of Outlook, or the biannual review.</p>
<p>It&#8217;s also a Petri Dish of the germs that kill a company.  People don&#8217;t collaborate. People have to book meeting rooms just to have any kind of communication, and that communication is delayed until the meeting room can be booked or until the &#8220;weekly&#8221; standing meeting because nobody actually talks or can collaborate in a free flowing environment. If someone has a question, they must get up, find the target person&#8217;s cube and interrupt whatever they are doing, simply because they have no idea if they are busy or not and have wasted time walking many yards across a room just to get a quick answer, and as soon as they &#8220;peek in&#8221;, the unwanted distraction has occurred. Politics and backstabbing occur in a cubicle environment. People &#8220;go back&#8221; to their cubes to stew, and only communicate by email or instant messenger. How many times have you read a message or mail and misread the intention of the sender? How often has a sender sent you an email and beat the thing to your cube so he/she can interrupt you anyway, just to ensure that you&#8217;ve been &#8220;papered&#8221;? How many times have you heard gossip wafting over your cube?</p>
<p>Cubes are STUPID-expensive and?inefficient. A single cubicle can cost upwards of $2000. Each cube takes up large amounts of empty space. It is expensive to move, very heavy and incredibly bulky to store. They have all the character of a minivan. An area that has 5 cubicles can support 10 persons sitting around a large, comfortable table with the best chairs, open lighting, a possible view out the window and&#8230; wait for it&#8230; face-to-face interaction!</p>
<p>What I&#8217;ve found out as I&#8217;ve sat around a table with 6 colleagues is:</p>
<ul>
<li>You can&#8217;t lie to anyone when you stare them in the face 8 hours a day, 200 days a year</li>
<li>Nobody gossips, ever</li>
<li>There is no disciplinary action &#8212; your peers keep you on the straight and narrow &#8212; you have to face your colleagues and pull your weight</li>
<li>If you have a question, you either ask the person you&#8217;re working with, or you wait until they have a free moment</li>
<li>Meetings start and end on time, and most of the time, nobody gets up. We schedule meetings not only by looking at calendars, we actually go around the room and make sure that the time is good for everyone.</li>
<li>We more often than not eat lunch together at our table</li>
<li>There&#8217;s no heroes, no chumps, no wallflowers and everyone carries their own weight</li>
<li>If there is a knowledge gap that needs to be filled, the group will find a solution through pair programming, mentoring or pointing out the best places to find the information</li>
<li>There&#8217;s just not a lot of paper, ever</li>
<li>People TALK instead of EMAIL; the amount of time I&#8217;ve spent reading my email has dropped dramatically. I don&#8217;t even leave my email program up in plain site, anticipating some communication.</li>
<li>The room is bigger &#8212; with no walls, the air flows freely around the room, light comes in from the windows and shadows are cast by human beings</li>
<li>There are no &#8220;cold cubes&#8221; or &#8220;hot cubes&#8221; because of ceiling vent positioning</li>
<li>We&#8217;re all happy to come to work. <em>Stupid-happy</em>. We all get along. We know things about our families and care about making sure that everyone is lifted to make the team, and the company a better place</li>
<li>It&#8217;s better to &#8220;run with the Buffalo&#8221; instead of standing in your own poop with like a <strong>steer</strong></li>
</ul>
<p>And the biggest thing I&#8217;ve learned? We innovate. We invent. We create great code because we&#8217;ve combined our best practices. There&#8217;s no real &#8220;leader&#8221;, no &#8220;tail end charlie&#8221;. We write code with few bugs.</p>
<h3 style="text-align: center;">We get things done.</h3>
<p>I&#8217;m doing the best work of my career. I have the best working relationships of my career. I have the best bosses in my career, I know exactly what is expected of me, have confidence in my place in my group, and feel empowered and sometimes humbled by the abilities of my colleagues. I feel respected and willingly give respect. I am happy.</p>
<p>The cube has become a <em>Dinosaur Feed Pen</em>. It&#8217;s long past it&#8217;s sell-by date in the modern corporation. In fact, it might be the single-largest factor in an unhappy and unproductive environment. Let me tell you, the happier your workers are, the better off you are. Would you like happy or sad people to build your car? How about unhappy airline mechanics? Do you want people that write the code, the intellectual capital of your eCommerce or IT department to feel like people are watching them all the time, or that they will be constantly interrupted, or wasting time to go somewhere to &#8220;get some air&#8221;? Companies face the necessity of cutting budgets and squeezing dimes to make a dollar. Simply sitting around a table with a great wireless connection, a projector, screen, places to put cards and some whiteboard space, will yield huge dividends.</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2011/07/19/the-dinosaur-feed-pen/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using TDD to create a Python Django SSN validation</title>
		<link>http://gurovich.com/site/2010/03/30/ssn_validation_with_django/</link>
		<comments>http://gurovich.com/site/2010/03/30/ssn_validation_with_django/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 19:44:59 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Enterprise Development]]></category>
		<category><![CDATA[django advanced validation]]></category>
		<category><![CDATA[Django SSN Validation]]></category>
		<category><![CDATA[Django TDD]]></category>
		<category><![CDATA[frozensete]]></category>
		<category><![CDATA[Python TDD]]></category>
		<category><![CDATA[SSN Validation]]></category>

		<guid isPermaLink="false">http://gurovich.com/site/?p=1299</guid>
		<description><![CDATA[The Problem to Solve Many web applications collect financial information to submit as leads for loans, credit card applications, bank information or other purposes. To ensure that the submitted SSN is valid, a validation algorithm must be implemented against the submitted value. Many websites in their infancy check only for length and null, but there [...]]]></description>
			<content:encoded><![CDATA[<h2>The Problem to Solve</h2>
<p>Many web applications collect financial information to submit as leads for loans, credit card applications, bank information or other purposes.  To ensure that the submitted SSN is valid, a validation algorithm must be implemented against the submitted value.  Many websites in their infancy check only for length and null, but there is actually a formula that is published by the government to further qualify the SSN in the form field.  By validating this SSN further, the quality of the generated lead is increased, which will have direct impact on the value of the data.</p>
<p>The algorithm we&#8217;ll construct is based on the following formulaic instruction:</p>
<blockquote><p><em>&#8220;A valid SSN is determined by the following rules according to the website </em><a title="SSA validation utilities" href="http://www.ssa.gov/employer/ssnweb.htm" target="_blank"><em>http://www.ssa.gov/employer/ssnweb.htm</em></a></p>
<p><em>Area-Group-Serial (AAA-GG-SSSS) The Social Security number consists of nine (9) digits. The first three (3) digits denote the area (or State) where the application for an original Social Security number was filed.</em></p>
<p><em>Within each area, the group number (middle two (2) digits) range from 01 to 99 but are not assigned in consecutive order. For administrative reasons, group numbers issued first consist of the ODD numbers from 01 through 09 and then EVEN numbers from 10 through 98, within each area number allocated to a State. After all numbers in group 98 of a particular area have been issued, the EVEN Groups 02 through 08 are used, followed by ODD Groups 11 through 99.</em></p>
<p><em>Within each group, the serial numbers (last four (4) digits) run consecutively from 0001 through 9999.&#8221;</em></p></blockquote>
<p>So, for reference, just in case:  The first three digits are the &#8220;Area&#8221; reference.  The second two digits are the &#8220;Group&#8221; reference, and the final four digits are the &#8220;Serial Number&#8221; value.</p>
<p>We&#8217;ll create a validator that checks to ensure that the social security number is the right length (stripped of dashes and white spaces), is all numbers, and finally implements the Social Security Administration&#8217;s formula for the Area/Group validation and their list of invalid SSNs.<span id="more-1299"></span></p>
<h2>What is needed</h2>
<p>The data for Area/Group validation and invalid SSN&#8217;s is quite static. ?For performance reasons, it is not necessary or reasonable to create a database to manage this data when a simple list can be used. ?In this particular implementation, we&#8217;ll <em>hard code</em> these values into a <code>dictionary</code> constant and create a <code>frozenset</code> to make the lookup and validation of the SSN Area even faster.  The list of invalid SSNs will also be a frozenset.</p>
<h3>Why frozenset</h3>
<p>I use a Python <code>set</code> because I&#8217;m just testing &#8220;membership&#8221; in the group.  This gives me optimization.  Further I decided to use <code>frozenset</code> because it&#8217;s API is limited further, not allowing updates, ordering or indexing.  I want to use these values as a constant that is loaded into the VM at run-time and does not depend on any database lookup for performance reasons.</p>
<h3>Project Structure</h3>
<p>The file structure is a typical Django Project with an &#8220;application&#8221; subdirectory.  The application subdirectory is called <code>finvs</code>, short for &#8220;financial validators&#8221;.  By using the <code>manage.py startapp finvs</code>, you&#8217;ll get the basic structure of the <code>finvs</code> automatically, and then you can add the <code>utils</code> subdirectory to abstract your algorithms and validation objects away from the actual application.</p>
<p>Note that a <code>tests.py</code> file has been created automatically.  When running <code>manage.py test {app}</code> the tests that are located in the tests.py of each {app} directory &#8212; in this case <code>finvs</code>, will be run.  Once everything is set up, we will explain how to use the tests to develop the actual implementation used in the <code>validation_formulas.py</code> file without ever having to start the Django server.  This means that you won&#8217;t have to develop a lot of front end code or do anything that you don&#8217;t need to do.  You can develop in an independent manner and work on the code that is a priority.</p>
<pre>project_root
        |-finvs
                |-utils
                        |-__init__.py
                        |-ssn_constants.py
                        |-validation_formulas.py
                |-__init__.py
                |-models.py
                |-tests.py
                |-views.py
        |-__init__.py
        |-manage.py
        |-settings.py
        |-urls.py</pre>
<p>For the purposes of this demonstration, the only files we&#8217;ll be using in this structure are <code>finvs/utils/ssn_constants.py</code> to hold the data in a &#8220;persistence layer&#8221;, <code>finvs/utils/validation_formulas.py</code> to contain the actual implementation method(s) of the validation, and <code>finvs/tests.py</code> to test and develop the code before I actually implement it. </p>
<h2>The &#8220;Persistence Layer&#8221;</h2>
<p>As described above, having all the information in a database requires too much overhead and is a drag on performance of the validation.  Having to suffer through a lookup to a database and the maintenance of this data involves more work and runtime cost than is necessary for what is very static data that rarely changes. </p>
<p>Since there are only a few hundred records to deal with, there is very little memory overhead taken up holding these values as static members.  I therefore created a file in the <code>utils</code> directory that contains the data I will use to validate SSNs against (<code>ssn_constants.py</code>).  The code I inserted is enumerated in its entirety below:</p>
<pre>finvs/utils/ssn_constants.py</pre>
<pre># a dictionary of area/group field values.
#The values represent the "high value" to be
# used with the SSN validation algorithm.
SSN_HIGH_VALUES ={
"001":"04","002":"02","001":"04","002":"02","003":"02","004":"06","005":"06","006":"06",
"007":"06","008":"90","009":"88","010":"90","011":"88","012":"88","013":"88","014":"88",
"015":"88","016":"88","017":"88","018":"88","019":"88","020":"88","021":"88","022":"88",
"023":"88","024":"88","025":"88","026":"88","001":"04","002":"02","003":"02","004":"06",
"005":"06","006":"06","007":"06","008":"90","009":"88","010":"90","011":"88","012":"88",
"013":"88","014":"88","015":"88","016":"88","017":"88","018":"88","019":"88","020":"88",
"021":"88","022":"88","023":"88","024":"88","025":"88","026":"88","027":"88","028":"88",
"029":"88","030":"88","031":"88","032":"88","033":"88","034":"88","035":"72","036":"70",
"037":"70","038":"70","039":"70","040":"08","041":"08","042":"08","043":"08","044":"08",
"045":"08","046":"08","047":"08","048":"08","049":"08","050":"96","051":"96","052":"96",
"053":"96","054":"96","055":"94","056":"94","057":"94","058":"94","059":"94","060":"94",
"061":"94","062":"94","063":"94","064":"94","065":"94","066":"94","067":"94","068":"94",
"069":"94","070":"94","071":"94","072":"94","073":"94","074":"94","075":"94","076":"94",
"077":"94","078":"94","079":"94","080":"94","081":"94","082":"94","083":"94","084":"94",
"085":"94","086":"94","087":"94","088":"94","089":"94","090":"94","091":"94","092":"94",
"093":"94","094":"94","095":"94","096":"94","097":"94","098":"94","099":"94","100":"94",
"101":"94","102":"94","103":"94","104":"94","105":"94","106":"94","107":"94","108":"94",
"109":"94","110":"94","111":"94","112":"94","113":"94","114":"94","115":"94","116":"94",
"117":"94","118":"94","119":"94","120":"94","121":"94","122":"94","123":"94","124":"94",
"125":"94","126":"94","127":"94","128":"94","129":"94","130":"94","131":"94","132":"94",
"133":"94","134":"94","135":"17","136":"17","137":"17","138":"17","139":"17","140":"17",
"141":"15","142":"15","143":"15","144":"15","145":"15","146":"15","147":"15","148":"15",
"149":"15","150":"15","151":"15","152":"15","153":"15","154":"15","155":"15","156":"15",
"157":"15","158":"15","159":"82","160":"82","161":"82","162":"82","163":"82","164":"82",
"165":"82","166":"82","167":"82","168":"82","169":"82","170":"82","171":"82","172":"82",
"173":"82","174":"82","175":"82","176":"82","177":"82","178":"82","179":"82","180":"82",
"181":"82","182":"82","183":"82","184":"82","185":"82","186":"82","187":"82","188":"82",
"189":"82","190":"82","191":"82","192":"82","193":"82","194":"82","195":"82","196":"82",
"197":"82","198":"82","199":"82","200":"82","201":"82","202":"82","203":"82","204":"82",
"205":"82","206":"82","207":"80","208":"80","209":"80","210":"80","211":"80","212":"75",
"213":"75","214":"75","215":"75","216":"73","217":"73","218":"73","219":"73","220":"73",
"221":"04","222":"02","223":"99","224":"99","225":"99","226":"99","227":"99","228":"99",
"229":"99","230":"99","231":"99","232":"53","233":"51","234":"51","235":"51","236":"51",
"237":"99","238":"99","239":"99","240":"99","241":"99","242":"99","243":"99","244":"99",
"245":"99","246":"99","247":"99","248":"99","249":"99","250":"99","251":"99","252":"99",
"253":"99","254":"99","255":"99","256":"99","257":"99","258":"99","259":"99","260":"99",
"261":"99","262":"99","263":"99","264":"99","265":"99","266":"99","267":"99","268":"11",
"269":"11","270":"11","271":"11","272":"11","273":"11","274":"11","275":"11","276":"11",
"277":"11","278":"11","279":"11","280":"11","281":"11","282":"11","283":"11","284":"11",
"285":"11","286":"11","287":"11","288":"11","289":"11","290":"11","291":"11","292":"11",
"293":"11","294":"11","295":"11","296":"08","297":"08","298":"08","299":"08","300":"08",
"301":"08","302":"08","303":"31","304":"29","305":"29","306":"29","307":"29","308":"29",
"309":"29","310":"29","311":"29","312":"29","313":"29","314":"29","315":"29","316":"29",
"317":"29","318":"04","319":"04","320":"04","321":"04","322":"04","323":"04","324":"04",
"325":"04","326":"04","327":"04","328":"04","329":"04","330":"04","331":"04","332":"04",
"333":"04","334":"04","335":"04","336":"04","337":"04","338":"04","339":"04","340":"04",
"341":"04","342":"04","343":"04","344":"04","345":"04","346":"04","347":"04","348":"04",
"349":"04","350":"04","351":"04","352":"04","353":"04","354":"04","355":"04","356":"04",
"357":"04","358":"04","359":"04","360":"04","361":"04","362":"33","363":"33","364":"33",
"365":"33","366":"33","367":"33","368":"31","369":"31","370":"31","371":"31","372":"31",
"373":"31","374":"31","375":"31","376":"31","377":"31","378":"31","379":"31","380":"31",
"381":"31","382":"31","383":"31","384":"31","385":"31","386":"31","387":"27","388":"27",
"389":"27","390":"27","391":"27","392":"27","393":"27","394":"27","395":"25","396":"25",
"397":"25","398":"25","399":"25","400":"65","401":"65","402":"65","403":"65","404":"65",
"405":"63","406":"63","407":"63","408":"99","409":"99","410":"99","411":"99","412":"99",
"413":"99","414":"99","415":"99","416":"59","417":"59","418":"59","419":"59","420":"59",
"421":"59","422":"59","423":"59","424":"57","425":"99","426":"99","427":"97","428":"97",
"429":"99","430":"99","431":"99","432":"99","433":"99","434":"99","435":"99","436":"99",
"437":"99","438":"99","439":"99","440":"21","441":"21","442":"21","443":"21","444":"21",
"445":"21","446":"21","447":"19","448":"19","449":"99","450":"99","451":"99","452":"99",
"453":"99","454":"99","455":"99","456":"99","457":"99","458":"99","459":"99","460":"99",
"461":"99","462":"99","463":"99","464":"99","465":"99","466":"99","467":"99","468":"47",
"469":"47","470":"47","471":"47","472":"47","473":"47","474":"47","475":"47","476":"47",
"477":"45","478":"37","479":"35","480":"35","481":"35","482":"35","483":"35","484":"35",
"485":"35","486":"23","487":"23","488":"23","489":"23","490":"23","491":"23","492":"23",
"493":"23","494":"23","495":"23","496":"23","497":"23","498":"21","499":"21","500":"21",
"501":"31","502":"31","503":"39","504":"37","505":"51","506":"49","507":"49","508":"49",
"509":"25","510":"25","511":"25","512":"25","513":"25","514":"25","515":"25","516":"43",
"517":"41","518":"73","519":"73","520":"51","521":"99","522":"99","523":"99","524":"99",
"525":"99","526":"99","527":"99","528":"99","529":"99","530":"99","531":"59","532":"59",
"533":"57","534":"57","535":"57","536":"57","537":"57","538":"57","539":"57","540":"71",
"541":"71","542":"69","543":"69","544":"69","545":"99","546":"99","547":"99","548":"99",
"549":"99","550":"99","551":"99","552":"99","553":"99","554":"99","555":"99","556":"99",
"557":"99","558":"99","559":"99","560":"99","561":"99","562":"99","563":"99","564":"99",
"565":"99","566":"99","567":"99","568":"99","569":"99","570":"99","571":"99","572":"99",
"573":"99","574":"45","575":"99","576":"99","577":"41","578":"41","579":"41","580":"37",
"581":"99","582":"99","583":"99","584":"99","585":"99","586":"57","587":"97","589":"99",
"590":"99","591":"99","592":"99","593":"99","594":"99","595":"99","596":"80","597":"80",
"598":"80","599":"80","600":"99","601":"99","602":"57","603":"57","604":"55","605":"55",
"606":"55","607":"55","608":"55","609":"55","610":"55","611":"55","612":"55","613":"55",
"614":"55","615":"55","616":"55","617":"55","618":"55","619":"55","620":"55","621":"55",
"622":"55","623":"55","624":"55","625":"55","626":"55","627":"02","628":"02","629":"02",
"630":"02","631":"02","632":"02","633":"02","634":"02","635":"02","636":"02","637":"02",
"638":"02","639":"02","640":"02","641":"02","642":"98","643":"98","644":"98","645":"98",
"646":"86","647":"86","648":"40","649":"38","650":"40","651":"38","652":"38","653":"38",
"654":"22","655":"22","656":"22","657":"22","658":"20","659":"12","660":"12","661":"12",
"662":"12","663":"10","664":"10","665":"10","667":"30","668":"28","669":"28","670":"28",
"671":"28","672":"28","673":"28","674":"28","675":"28","676":"10","677":"10","678":"10",
"679":"09","680":"76","681":"10","682":"09","683":"09","684":"09","685":"09","686":"09",
"687":"09","688":"09","689":"09","690":"09","691":"03","692":"03","693":"03","694":"03",
"695":"03","696":"03","697":"03","698":"03","699":"01","700":"18","701":"18","702":"18",
"703":"18","704":"18","705":"18","706":"18","707":"18","708":"18","709":"18","710":"18",
"711":"18","712":"18","713":"18","714":"18","715":"18","716":"18","717":"18","718":"18",
"719":"18","720":"18","721":"18","722":"18","723":"18","724":"28","725":"18","726":"18",
"727":"10","728":"14","729":"07","730":"05","731":"05","732":"05","733":"05","750":"05",
"751":"03","756":"01","757":"01","758":"01","759":"01","760":"01","761":"01","762":"01",
"764":"62","765":"62","766":"48","767":"48","768":"48","769":"48","770":"48","771":"46",
"772":"46"
}

# frozenset makes for quick access to the key fields of the SSN high values
# the key fields are the 'areas'
VALID_SSN_AREAS = frozenset(SSN_HIGH_VALUES.keys())

# a frozenset of invalid ssn numbers
INVALID_SSN_NUMBERS = frozenset([
"002281852","042103580","062360749","078051120",
"095073645","128036045","135016629","141186941",
"165167999","165187999","165207999","165227999",
"165247999","189092294","212097694","212099999",
"306302348","308125070","468288779","549241889",
"987654320","987654321","987654322","987654323",
"987654324","987654325","987654326","987654327",
"987654328","987654329"])</pre>
<h2>The Test Harness</h2>
<p>Description of the Test</p>
<p>There are a few parts to the test.  I built it in a few steps.  first, the <code>setUp</code> method creates a &#8220;Good&#8221; SSN, &#8220;Good&#8221; Group and &#8220;Good&#8221; High Group values.  The &#8220;High Group&#8221; is that value that is highest allowed for the particular &#8220;Area&#8221; value.  The first method, <code>testSSNValidation(self)</code> is a test of the implementation with a known good serial number.  This is the first method that I wrote, because this is where I &#8220;worked out&#8221; the algorithm that I wanted to use in the implementation. </p>
<p>Once I got the &#8220;right answer&#8221;, I could create another test method to throw a whole bunch of numbers at it to ensure that it is working right under all circumstances and border conditions.  Note the extensive documentation &#8212; you may be passing this code off to another team in the future, and it&#8217;s important to leave a good trail.  Validation this complicated is not <i>self documenting</i>.  Walking through the method, I first created the return value that I wanted to use and made it <code>False</code> so that if any validation failed it would fall through and just return.  Once the default was set, I stripped out any hyphens and whitespace, I checked the value for length, then check to ensure that the Area (first three digits) is valid.  If the number passes all these tests, we can then go into the <I>private method</i> that I created to implement the &#8220;high values&#8221; formula <code>__isGroupValid(self,group,groupHighestValue)</code>:</p>
<p><sup><em>Note: this is a pretty complex formula so I&#8217;m not going to get into the gritty details &#8212; see the SSA site for more info&#8230;</em></sup></p>
<pre>finvs/tests.py</pre>
<pre>"""
This file tests the finvs application
"""
import unittest
from django.test import TestCase
from finvs.utils.validation_formulas import ValidationFormulas
from finvs.utils.ssn_constants import SSN_HIGH_VALUES
from finvs.utils.ssn_constants import INVALID_SSN_NUMBERS
from finvs.utils.ssn_constants import VALID_SSN_AREAS

class ValidatorsTestCase(unittest.TestCase):

    GOOD_SSN = ' '
    GOOD_GRP = 0
    GOOD_HIGH_GRP_VAL = 0

    def setUp(self):
        self.GOOD_SSN = '526-33-4563'
        self.GOOD_GRP = 33
        self.GOOD_HIGH_GRP_VAL = 99

   def testSSNValidation(self):
        """Tests the algorithm in the validator against
            known high values for the first three digits

           Validate a Social Security Number (SSN). A valid SSN
            is determined by the following rules according to the
            website http://www.ssa.gov/employer/ssnweb.htm

           Area-Group-Serial (AAA-GG-SSSS) The Social Security
            number consists of nine (9) digits. The first three
            (3) digits denote the area (or State) where the application
            for an original Social Security number was filed.

           Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.

           Within each group, the serial numbers (last four (4) digits)
            run consecutively from 0001 through 9999.
           """
    def testSSNAlgorithm(self):
        bool=False
        ssn_v=self.GOOD_SSN.translate(None,'-')
        ssn_v=ssn_v.strip()
        #print("SSN: %s" % (ssn_v))
        if (len(ssn_v)==9 and ssn_v.isdigit()):
            #print("SSN passed for length and digits: %s" % (ssn_v))
            key_v = ssn_v[3:5]
            if ssn_v[0:3] in VALID_SSN_AREAS:
                hg_v = SSN_HIGH_VALUES[ssn_v[0:3]]
                #check for valid group for Area ID in private method
                bool = self.__isGroupValid(int(key_v), int(hg_v))
            #print("VALID_GROUP: %s" % (bool))
        self.assertTrue(bool)

    def testIsValidSSN(self):
        validator = ValidationFormulas()
        self.assertTrue(validator.isValidSSN(self.GOOD_SSN))
        long_ssn = "   %s   " % (self.GOOD_SSN)
        self.assertTrue(validator.isValidSSN(long_ssn))
        stripped_ssn = self.GOOD_SSN.translate(None,'-')
        self.assertTrue(validator.isValidSSN(stripped_ssn))
        for bad_ssn in INVALID_SSN_NUMBERS:
            self.assertFalse(validator.isValidSSN(bad_ssn))
        bad_ssn = "742-51-1234"
        self.assertFalse(validator.isValidSSN(bad_ssn))

    def testGroupValidAlgorithm(self):
        self.assertTrue(self.__isGroupValid(self.GOOD_GRP,self.GOOD_HIGH_GRP_VAL))

    def testShowSSNAreas(self):
        self.assertEqual(len(SSN_HIGH_VALUES.keys()), len(VALID_SSN_AREAS))

    #-----------------Private Functions-------------------------------------------

def __isSSNGroupValid(self,group,groupHighestValue):

        """Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.
            """
        validGroup = False
        moduloGroupNumber = group % 2
        moduloGroupHighest = groupHighestValue % 2

        if ((moduloGroupHighest == 1) &#038; (groupHighestValue >= 1) &#038; (groupHighestValue <= 9)):             if ((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= groupHighestValue)):                 validGroup = True          elif ((moduloGroupHighest == 0) &#038; (groupHighestValue >= 10) &#038; (groupHighestValue <= 98)):             if (((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= 9))             | ((moduloGroupNumber == 0) &#038; (group >= 10) &#038; (group <= groupHighestValue))):                 validGroup = True          elif ((moduloGroupHighest == 0) &#038; (groupHighestValue >= 2) &#038; (groupHighestValue <= 8)):             if (((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= 9))             | ((moduloGroupNumber == 0) &#038; (group >= 10)
            &#038; (group <= 98))             | ((moduloGroupNumber == 0) &#038; (group >= 2)
            &#038; (group <= groupHighestValue))):                 validGroup = True          elif ((moduloGroupHighest == 1) &#038; (groupHighestValue >= 11) &#038; (groupHighestValue <= 99)):             if (((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= 9))             | ((moduloGroupNumber == 0) &#038; (group >= 10)
            &#038; (group <= 98))             | ((moduloGroupNumber == 0) &#038; (group >= 2)
            &#038; (group <= 8))             | ((moduloGroupNumber == 1) &#038; (group >= 11)
            &#038; (group <= groupHighestValue))):                 validGroup = True          return validGroup</pre>
<p>The next methods test and retest the algorithms, ensuring that bad numbers, numbers with white space and invalid numbers also return <code>False</code> for their tests.  More comprehensive tests can and should be written before this code goes into production, but there is now the basis for an implementation and transfer of our "test" code to <code>validation_formulas.py</code> </p>
<h2>The Implementation</h2>
<p>The implementation is almost "cut and paste" from the test at this point.  The private method is a complete clone, and the public validation method just changes a few things around to get the right information.  This particular implementation is somewhat basic, since it only returns <code>True</code> or <code>False<code> with the number submitted -- it doesn't tell the requestor exactly what happened, just that the number submitted is good or bad.  More sophistication can be added by returning pointers towards messages, then assigning a pointer for each test that fails.  A test with no failure could return a "zero", and after that messages could pile up.  </p>
<p>This is a good strategy for any sophisticated validation system, since there are few hard-core validations that need to have a binary response -- it is more important to have some "why" answers with a failed validation, and in some cases, validations may not "fail" in a particular manner.  One example of a "gray area" in validation would be in profanity filters.  Some lexicon may be quite profane to a particular user, where another may not.  In these particular cases, a "score" might be returned for verification instead of a binary.  Another case would be in Address fields -- ones that don't have a number followed by string of letters may not be a real address, but there are outliers that need to be covered...</p>
<pre>validation_formulas.py</pre>
<pre>#!/usr/bin/env python
# encoding: utf-8
"""
validation_formulas.py
Created by Danilo Gurovich on 2010-03-19.
"""
from finvs.utils.ssn_constants import *

class ValidationFormulas:

    #Validates Social Security Number
    def isValidSSN(self,ssn_str):
        """Validate a Social Security Number (SSN). A valid SSN
            is determined by the following rules according to the
            website http://www.ssa.gov/employer/ssnweb.htm

           Area-Group-Serial (AAA-GG-SSSS) The Social Security
            number consists of nine (9) digits. The first three
            (3) digits denote the area (or State) where the application
            for an original Social Security number was filed.

           Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.

           Within each group, the serial numbers (last four (4) digits)
            run consecutively from 0001 through 9999.
           """
        isValid=False
        #strip all the dashes and whitespace
        ssn_v=ssn_str.translate(None,'-')
        ssn_v=ssn_v.strip()
        #Check length and ensure that it's a digit
        if (len(ssn_v)==9 and ssn_v.isdigit()):
            #print("SSN passed for length and digits: %s" % (ssn_v))
            #Check to ensure that it's not an invalid number
            if(ssn_v not in INVALID_SSN_NUMBERS):
                key_v = ssn_v[3:5]
                if ssn_v[0:3] in VALID_SSN_AREAS:
                    hg_v = SSN_HIGH_VALUES[ssn_v[0:3]]
                    #check for valid group for Area ID in private method
                    isValid = self.__isSSNGroupValid(int(key_v), int(hg_v))

        return isValid

    #---------- Private Functions -------------------------------------------------------

def __isSSNGroupValid(self,group,groupHighestValue):

        """Within each area, the group number (middle two (2) digits)
            range from 01 to 99 but are not assigned in consecutive
            order. For administrative reasons, group numbers issued
            first consist of the ODD numbers from 01 through 09 and
            then EVEN numbers from 10 through 98, within each area
            number allocated to a State. After all numbers in group
            98 of a particular area have been issued, the EVEN Groups
            02 through 08 are used, followed by ODD Groups 11 through
            99.
            """
        validGroup = False
        moduloGroupNumber = group % 2
        moduloGroupHighest = groupHighestValue % 2

        if ((moduloGroupHighest == 1) &#038; (groupHighestValue >= 1) &#038; (groupHighestValue <= 9)):             if ((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= groupHighestValue)):                 validGroup = True          elif ((moduloGroupHighest == 0) &#038; (groupHighestValue >= 10) &#038; (groupHighestValue <= 98)):             if (((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= 9))             | ((moduloGroupNumber == 0) &#038; (group >= 10) &#038; (group <= groupHighestValue))):                 validGroup = True          elif ((moduloGroupHighest == 0) &#038; (groupHighestValue >= 2) &#038; (groupHighestValue <= 8)):             if (((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= 9))             | ((moduloGroupNumber == 0) &#038; (group >= 10)
            &#038; (group <= 98))             | ((moduloGroupNumber == 0) &#038; (group >= 2)
            &#038; (group <= groupHighestValue))):                 validGroup = True          elif ((moduloGroupHighest == 1) &#038; (groupHighestValue >= 11) &#038; (groupHighestValue <= 99)):             if (((moduloGroupNumber == 1) &#038; (group >= 1) &#038; (group <= 9))             | ((moduloGroupNumber == 0) &#038; (group >= 10)
            &#038; (group <= 98))             | ((moduloGroupNumber == 0) &#038; (group >= 2)
            &#038; (group <= 8))             | ((moduloGroupNumber == 1) &#038; (group >= 11)
            &#038; (group <= groupHighestValue))):                 validGroup = True          return validGroup</pre>
<h2>Why is this Cool?</h2>
<p>This whole way of developing code is cool because I don't need to fire up the server and drill through a bunch of pages to find out if I had "done it right".  In fact, I haven't even wrote the service that I want to connect to, and I haven't even filled out the model in the application that I'm working in.  I'm just doing one piece at a time, then building the model and service once I have everything ironed out.  I'll have super-duper test coverage without writing my code twice, and really have confidence in the entire back-end as I build the view and controller modules out, buying plenty of time to optimize, refactor and work everything into some nice design patterns (<em>Strategy</em>, anyone?)</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2010/03/30/ssn_validation_with_django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Process and Situational Awareness for eCommerce Development</title>
		<link>http://gurovich.com/site/2010/03/23/process-and-situational-awareness-for-ecommerce-development/</link>
		<comments>http://gurovich.com/site/2010/03/23/process-and-situational-awareness-for-ecommerce-development/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 13:03:36 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[Dev process]]></category>
		<category><![CDATA[Enterprise Development]]></category>
		<category><![CDATA[Business and Technology alignment]]></category>
		<category><![CDATA[Development Processes]]></category>
		<category><![CDATA[eCommerce Development Processes]]></category>
		<category><![CDATA[eCommerce Management]]></category>
		<category><![CDATA[Metrics and eCommerce]]></category>

		<guid isPermaLink="false">http://danilogurovich.wordpress.com/2007/06/12/process-and-situational-awareness-for-ecommerce-development/</guid>
		<description><![CDATA[Update from an article originally published by me in 2007 Alignment is everything For many years, managers in the software industry submitted budgets that were unrealistic to Business Unit managers that had no clue as to what to question, what to approve or where to cut. As business has grown up and increased its expectations [...]]]></description>
			<content:encoded><![CDATA[<p><sup><i>Update from an article originally published by me in 2007</i></sup></p>
<h2>Alignment is everything</h2>
<p>For many years, managers in the software industry submitted budgets that were unrealistic to Business Unit managers that had no clue as to what to question, what to approve or where to cut. As business has grown up and increased its expectations of IT departments, Development and Infrastructure has also been forced to mature and face the fact that they aren&#8217;t an &#8220;overhead&#8221; cost. This is especially true in eCommerce.</p>
<h2>The Best is the enemy of the Good</h2>
<p>I&#8217;ve never met an Engineer or Manager of Engineers that didn&#8217;t see an infrastructure project as vital to the organization&#8217;s ongoing health and stability. I&#8217;ve seen (and <em>been</em>) that Manager before. They&#8217;ve actually been wrong more than they&#8217;ve been right. The reason for this is the lack of a complete picture of the goals of the organization as a whole, the priorities for various Development/Infrastructure (DEV-INF) projects, and the fact that budgeting exists because <i>resources are finite</i>. Sometimes an eCommerce site can limp along for years on a code base that is far from the ideal architecturally, but it may cost far less to maintain and extend it than to upgrade it to the &#8220;Next Great Killer Platform&#8221; at the cost of revenue-driven projects.</p>
<h2>The Holistic view of a Budget</h2>
<p>While all projects will have some value, it&#8217;s important to prioritize projects in alignment with the overall organization&#8217;s strategy and objectives. There is no use in a complete re-architecture of the site when current demands of Marketing, Consumer Experience and other various Business Units cannot be met. The goal in eCommerce is simple. Keep the business growing, keep the site in &#8220;five nines&#8221;, and refine the user experience to increase conversion. DEV-INF budgets must play in this ballpark or, as a development leader, all credibility with Business Units will be lost; ultimately will leding to a breakdown in communications between Engineering and Business, which is a crisis in an eCommerce workplace.</p>
<h2>Metrics are the key</h2>
<p>Once projects are aligned with Corporate Objectives, it&#8217;s vital to show all cost drivers for these expenses. Many times the cost of ongoing maintenance is not factored in, but can be as much as 65% of an overall budget. This is also true for time budgeted for QE/QA. While the individual Engineer writing code may only write 250 lines that finally make it into production in a three-month long project, how many times he/she had to write it, how much time was eaten up managing and checking this code, and finally what documentation, knowledge transfer and future extendibility these 250 lines will have also affect costs. All these things must be taken into consideration.</p>
<p>Budgeting isn&#8217;t just all planning. Once the planning is complete, the spending begins. Vital in this aspect is accountability and assessment of performance. Hard, industry-standard metrics exist to gauge the performance of DEV-INF budget items. In eCommerce I&#8217;ve found many easily measured values:</p>
<ol>
<li>Actual vs. Proposed Development times.</li>
<li>Actual vs. Proposed Resources.</li>
<li>Pre-release bugs.</li>
<li>Post-release bugs.</li>
<li>Effects upon site stability and performance.</li>
<li>Did the Project &#8220;Do&#8221; what the owners said it would do?</li>
<li>Were the expectations of Business Units met, and are these stakeholders satisfied with the results?</li>
<li>Did any problems that come up get handled in appropriate manners?</li>
<li>Were in-place processes broken?</li>
</ol>
<h2>Approaches</h2>
<p>Approaches to DEV-INF budgeting should be aligned with the current culture and expectations of the Business. They must have significant buy-in by various business stakeholders. If business drivers have &#8220;skin in the game&#8221; as to line-items in a DEV-INF budget, this automatically give credibility to it and also act as a check to make sure that I&#8217;ve done my homework. Many successful organizations use the <i>Consolidated Projects Approach</i> to budgeting and allocation for DEV-INF projects with outstanding success. In a nutshell:</p>
<p>Consolidated Projects List basic points:</p>
<ul>
<li>IT budget planning process starts before the organization&#8217;s process.</li>
<li>IT managers submit summary project data for consolidation into a single spreadsheet</li>
<li>These projects are then sorted and prioritized by DEV-INF managers before submission to the overall business Prioritization Committee.</li>
<li>The Prioritization Committee decides how these projects are to be aligned, budgeted and implemented within the entire Organization&#8217;s overall Business needs and strategies.</li>
</ul>
<p>This approach provides Senior Executives with a complete picture of all proposed projects, their costs, and priority ranking; these units will have a &#8220;30,000 foot&#8221; picture to make a more informed decision. Total project requirements may now be viewed as a single picture to senior management; priorities become a decision factor. No single group can drive pet projects or non-revenue generating development without prioritization or fully understanding what the business impact or opportunity costs involved are.</p>
<p>This process may be extended with <i>Gate Checks</i> to assure relevance to the goals of the company as time changes. This is especially true with larger organizations that may be widely distributed.  Projects can often times have huge scope (ah &#8212; to de-scope, another topic!) and can take months of development time.? The needs of a business can change over this period, and any project that is underway should have enough flexibility to move with the times or the business stakeholders or group as a whole should have the gumption to kill or suspend development indefinitely or until such time as solid metrics warrant completion.</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2010/03/23/process-and-situational-awareness-for-ecommerce-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Test Driven Development with Django Unit Testing</title>
		<link>http://gurovich.com/site/2010/03/20/test-driven-development-with-django-unit-testing/</link>
		<comments>http://gurovich.com/site/2010/03/20/test-driven-development-with-django-unit-testing/#comments</comments>
		<pubDate>Sat, 20 Mar 2010 16:56:20 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[Enterprise Development]]></category>
		<category><![CDATA[Django TDD]]></category>
		<category><![CDATA[Django Test Driven Development]]></category>
		<category><![CDATA[Django Unit Testing]]></category>
		<category><![CDATA[Django unittest]]></category>
		<category><![CDATA[python unit testing]]></category>
		<category><![CDATA[TDD python]]></category>
		<category><![CDATA[unittest python]]></category>

		<guid isPermaLink="false">http://gurovich.com/site/?p=1266</guid>
		<description><![CDATA[Django has wonderful unit testing functionality built into the framework. It is often ignored because Django gives so much functionality &#8220;out of the box&#8221;, but this doesn&#8217;t mean that one shouldn&#8217;t do &#8220;their part&#8221; when extending the framework to build your own applications. Tests are a great way to &#8220;figure out&#8221; what needs to be [...]]]></description>
			<content:encoded><![CDATA[<p>Django has wonderful unit testing functionality built into the framework. It is often ignored because Django gives so much functionality &#8220;out of the box&#8221;, but this doesn&#8217;t mean that one shouldn&#8217;t do &#8220;their part&#8221; when extending the framework to build your own applications.  Tests are a great way to &#8220;figure out&#8221; what needs to be done, then actually taking what you&#8217;ve learned to implement in the application proper.</p>
<p>My attempt here is to show how I used TDD in an Django application.  We&#8217;ll create a basic project with a single application and use unit testing to figure out an algorithm an implement it in the application&#8217;s class.<span id="more-1266"></span></p>
<h3>Why Test at All?</h3>
<p>I&#8217;ve spoken to many groups about Test Driven Development (TDD).  Many experienced engineers don&#8217;t do it because they haven&#8217;t been indoctrinated into the practice early, and they are established in an organization where they maintain and extend code that they might have been writing for months or even years.  The code has been fully tested and it is solid.  Why write unit tests?</p>
<p>Newer developers don&#8217;t know how to start with tests.  They write code, then write tests, then get frustrated because they are continuously writing code twice.  Corners get cut, and at best you get the &#8220;bare minimum&#8221; of coverage, which is basically what the boss sees and reviews.</p>
<p>Both of these scenarios are unfortunate, because there are a few things that TDD gives gives all engineers and the organizations that they work for:</p>
<ul>
<li>More efficient QA. QA engineers and testers don&#8217;t have to test for functionality, and they get better quality code.?What does this mean? It means that they get to do the part of their job that is more meaningful to the company as a whole. If the basic code and functionality are automatically tested, QA can then find the border conditions and those evil underlying non-obvious bugs that can kill an application, and if large enough, kill a company&#8217;s profits.</li>
<li>Better and more cohesive organizations. Test Driven Development builds confidence throughout the entire organization. Engineers working often in geographically dispersed groups need to &#8220;trust&#8221; each other, their skills and abilities. If everyone in the organization is using TDD, these groups will know that the quality coming from others will work. This not only creates trust amongst engineers, but throughout the organization, from Marketing and Business resources all the way through QA.</li>
<li>Professionalism. Being a &#8220;Pro&#8221; doesn&#8217;t mean generating thousands of lines of code.?It means generating efficient, simple to maintain, easily configurable code that &#8220;just works&#8221; every time. It not only has to work, it has to be tested and documented.</li>
<li>Peer pressure to &#8220;do the right thing&#8221;. If the senior members and thought leaders of an engineering group are all using TDD, documenting their code and communicating effectively, this will spread throughout the organization and foment a best practices environment.</li>
</ul>
<p>Test Driven Development with high unit test coverage creates efficient, spirited and profitable software. The balance of this post will explain just how I use TDD to implement a complex Bank Routing Number (ABN) validation class. I am assuming that the reader is familiar with Django, and has a comfortable understanding with basic Django and Python development principles:</p>
<h3>Create the Project and Application</h3>
<p>My application&#8217;s name is</p>
<pre>valid_lib</pre>
<p>It is destined to be a Service Platform that allows all kinds of complex financial form data to be validated through a ReSTful interface. At the moment I&#8217;m not worried about the Service, the Interfaces or even the Business Model. Currently, I want to get all the validation algorithms and calculations in place. The rest of the stuff is pretty easy.  At the command line, in my Django development directory, I type:</p>
<pre>django-admin.py startproject valid_lib</pre>
<p>To start my project.  I <code>cd</code> into the <code>valid_lib</code> directory and then type:</p>
<pre>django-admin.py startapp finvs</pre>
<p>To create my application and it&#8217;s directory.  At this point I add the <code>valid_lib.finvs</code> to my <code>INSTALLED_APPS</code> in the the <code>settings.py</code> file, and while I&#8217;m there I add my database information, even though I really won&#8217;t be using it yet. I also add another folder in the <code>finvs</code> directory that I name <code>util</code>.  Run a <code>manage.py syncdb</code> against the application&#8217;s root and you should be good to go.  Everything should now look like fig 1:</p>
<div id="attachment_1268" class="wp-caption aligncenter" style="width: 204px"><a href="http://gurovich.com/site/wp-content/uploads/2010/03/fig1.png"><img class="size-full wp-image-1268 " title="Initial TDD validation app structure" src="http://gurovich.com/site/wp-content/uploads/2010/03/fig1.png" alt="" width="194" height="222" /></a><p class="wp-caption-text">fig 1: Initial TDD validation app structure</p></div>
<p><em>(I&#8217;m writing this on my MacBook Pro and using Textmate, but you should be getting similar results however you&#8217;re doing it)</em></p>
<p>Notice that there is a <code>test.py </code> file in the<code> finvs </code>directory.  This is where we&#8217;re going to start.  Django&#8217;s default unit testing fixture looks for this file and will execute tests within it.  We&#8217;ll open that file up and begin writing our code there.</p>
<h3>ABN Validation</h3>
<p>ABA (American Banker&#8217;s Association) routing numbers (ABNs) are used to identify financial institutions when making transactions. This number is usually required when setting up a bank account for direct deposits, automated payments, etc. Or when making payments by &#8220;paperless&#8221; check over the phone or online.</p>
<p>These routing numbers include a checksum digit which can be used to help verify if a given number is valid or not.</p>
<p>The algorithm checks the first second and third number and adds them together, then iterates through every three numbers (total of 9) to return a value. If the resulting sum is an even multiple (think <code>modulus</code> here&#8230;) of ten (but not zero), the ABA routing number is good. ?We&#8217;ll now write a test with a valid ABN to see if we can get things to work correctly.  In the <code>tests.py</code> file, write:</p>
<pre>
"""
This file tests the finvs application
"""
import unittest
from django.test import TestCase

#Here are some bank numbers that we can run tests against...
SHORT_BAD_ABN_NUM = 1000012
LONG_BAD_ABN_NUM = 255073345999
BAD_ABN_NUM = 255073545
GOOD_ABN_NUM = 255073345

class ValidatorsTestCase(unittest.TestCase):

    def setUp(self):
        self.value = CITY_CODE_FRAUD

    def testAbnAlgorythm(self):
        """Tests the algorythm with a known good bank number.
           This test is here to create the algorythm to be used
             in the validator implementation.  When it's right,
             cut and paste it into the validator class.

           The algorithm checks the first second and third number
            and adds them together, then iterates through every
            three numbers (total of 9) to return a value.

           If the resulting sum is an even multiple of ten
            (but not zero), the ABA routing number is good.
           """
        n=0
        bank_str = str(GOOD_ABN_NUM)
        num_length = len(bank_str)
        if (num_length ==9):
            for j in range(0,num_length,3):
                t = int(bank_str[j]) #this is the first digit
                ti = int(bank_str[j + 1]) #this is the second digit
                tii = int(bank_str[j + 2]) #this is the third digit
                n += (t * 3)+ (ti * 7)+ tii #add them up
            #check for zero and modulus of 10
            print((n != 0) &#038; ((n % 10) == 0))  #we'll take this line out when we get it right.
            self.assertTrue((n != 0) &#038; ((n % 10) == 0))
</pre>
<p>Now, at the application root, run:</p>
<pre>python manage.py test finvs.ValidatorsTestCase</pre>
<p>You should get something very similar to this:</p>
<pre>
$ python manage.py test finvs.ValidatorsTestCase
Creating test database...
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Installing index for auth.Permission model
Installing index for auth.Message model
True
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
Destroying test database...
</pre>
<p>The <b><code>True</code></b> that you see in the output is your print statement. Notice that the system also creates and destroys a test database.  This is extremely cool functionality that can be used with Django&#8217;s Fixtures, but we&#8217;re not going to use it here for this code set.  We haven&#8217;t written a line of production code, but our test passes, and if you look at the test, <i>it is the basis for the actual implementation</i>!</p>
<h3>Implement It!</h3>
<p>We&#8217;re really close, but we&#8217;ll need to make a few changes before we implement it in our &#8220;production&#8221; code.  Seriously, we&#8217;re really close!</p>
<p>In the <code>utils</code> directory, create the file <code>validation_formulas.py</code>  This is where we&#8217;ll add our ABN validation class.  In my test code I created a check to ensure that the number sent in had exactly 9 digits.  I did this because I didn&#8217;t want to have a <code>try / except</code> block, and to keep it clean. Feel free to add this if needed.  The other change is that we actually need to return something &#8212; True or False in this case.  The test code&#8217;s <code>def</code> doesn&#8217;t return anything, it just makes an assertion.  To validate something, we need to insert a parameter into the method and then return a true/false.  We also need to give it a name.  In the <code>validation_formulas.py</code> file, you can now insert:</p>
<pre>
class ValidationFormulas:

    def isBankRoutingNumber(self,bankNumber):
        """Parses the bank routing number for purposes of finding a fraudulent entry.
            the algorithm check the first second and third number and adds them together,
            then iterates through every three numbers (total of 9) to return a value.

           If the resulting sum is an even multiple of ten (but not zero), the ABA
            routing number is good.

           param -- bankNumber the 9 digit bank number;

           return boolean true if number is valid, false if not. false is the default
           """
        n=0
        retbool=False
        bank_str = str(bankNumber)
        num_length = len(bank_str)
        if (num_length ==9):
            for j in range(0,num_length,3):
                t = int(bank_str[j])
                ti = int(bank_str[j + 1])
                tii = int(bank_str[j + 2])
                n += (t * 3)+ (ti * 7)+ tii
            retbool = (n != 0) &#038; ((n % 10) == 0)
        #return the value
        return retbool
</pre>
<p>Notice the added documentation.  Some of it is cut and paste from the Test, the rest is information that you&#8217;ll want to convey to anyone that is using this code in the future, because hopefully at some point the company you work for will realize just how brilliant you are and promote you to CTO, where you won&#8217;t get to write code anymore.  You sure as heck don&#8217;t want to leave the poor schlep that is hired to take your place in the dark!</p>
<p>Also notice that I have a default return of <code>False</code>  some applications may need a different default return, or this return may be handled in a manager class that registers the default returns in some kind of persistence layer that is more dynamic.  Your mileage may vary.</p>
<h3>Wrapping it Up</h3>
<p>There it is.  You&#8217;ve written a test first.  You&#8217;ve used the implementation of the test and created a sensible implementation.  If there are other ways of refining your code or cleaning things up, you can always go back and make more changes.  But your&#8217;e not done.  You need to write more tests to actually <b>verify</b> that this algorithm works, that it shows false for bad routing numbers, and that it an spot when the length of the number is incorrect without throwing any index out of bounds exceptions or the like.  you can then add more test methods to your <code>ValidatorsTestCase</code> class.  I&#8217;ve also leveraged the <code>setUp</code> method that is provided with the framework to generate my constants for me. The code will then look like this:</p>
<pre>
"""
This file tests the finvs application
"""
import unittest
from django.test import TestCase
from valid_lib.finvs.utils.validation_formulas import ValidationFormulas

class ValidatorsTestCase(unittest.TestCase):

    def setUp(self):
        self.SHORT_BAD_ABN_NUM = 1000012
        self.LONG_BAD_ABN_NUM = 255073345999
        self.BAD_ABN_NUM = 255073545
        self.GOOD_ABN_NUM = 255073345

    def testAbnAlgorythm(self):
        """Tests the algorythm with a known good bank number.
           This test is here to create the algorythm to be used
             in the validator implementation.  When it's right,
             cut and paste it into the validator class.

           The algorithm checks the first second and third number
            and adds them together, then iterates through every
            three numbers (total of 9) to return a value.

           If the resulting sum is an even multiple of ten
            (but not zero), the ABA routing number is good.
           """
        n=0
        bank_str = str(self.GOOD_ABN_NUM)
        num_length = len(bank_str)
        if (num_length ==9):
            for j in range(0,num_length,3):
                t = int(bank_str[j])
                ti = int(bank_str[j + 1])
                tii = int(bank_str[j + 2])
                n += (t * 3)+ (ti * 7)+ tii
            self.assertTrue((n != 0) &#038; ((n % 10) == 0))

    def testBankRouter(self):
        """Tests the algorythm in the validator against
              known good and bad bank numbers.
           """
        bank_num = self.SHORT_BAD_ABN_NUM
        formt = ValidationFormulas()
        bool = formt.isBankRoutingNumber(bank_num)
        self.assertFalse(bool)

        bank_num = self.LONG_BAD_ABN_NUM
        formt = ValidationFormulas()
        bool = formt.isBankRoutingNumber(bank_num)
        self.assertFalse(bool)

        bank_num = self.BAD_ABN_NUM
        formt = ValidationFormulas()
        bool = formt.isBankRoutingNumber(bank_num)
        self.assertFalse(bool)

        bank_num = self.GOOD_ABN_NUM
        formt = ValidationFormulas()
        bool = formt.isBankRoutingNumber(bank_num)
        self.assertTrue(bool)</b>
</pre>
<p>I&#8217;ve added an import for the &#8220;production&#8221; class that i&#8217;m testing (<code>ValidationFormulas</code>).  Finally, I&#8217;ve added a new method that implements new tests against the actual methods in this class to check my work.  Running the tests now reveal:</p>
<pre>
Creating test database...
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Installing index for auth.Permission model
Installing index for auth.Message model
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
Destroying test database...
</pre>
<p> If someone in the future messes with the &#8220;production&#8221; code implementation and things get out of whack, It will break here instead of in front of the user.  By combining this with a continuous-build environments, a lot of mistakes can be caught extremely fast, sometimes within seconds of a source control check in!</p>
<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2010/03/20/test-driven-development-with-django-unit-testing/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Looking at Pinax &#8211; a Review</title>
		<link>http://gurovich.com/site/2010/03/05/looking-at-pinax-a-review/</link>
		<comments>http://gurovich.com/site/2010/03/05/looking-at-pinax-a-review/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 17:59:27 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Pinax]]></category>
		<category><![CDATA[Pinax Review]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://gurovich.com/site/?p=1239</guid>
		<description><![CDATA[Django has become a friend of mine over the last year.  I had previous experience with Ruby on Rails, and was always disappointed when it came to deploying and productizing the application, and the actual framework APIs and implementations underwent too many changes over the last few years to give me the confidence I needed [...]]]></description>
			<content:encoded><![CDATA[<p>Django has become a friend of mine over the last year.  I had previous experience with Ruby on Rails, and was always disappointed when it came to deploying and productizing the application, and the actual framework APIs and implementations underwent too many changes over the last few years to give me the confidence I needed to go into production with it.  Python has been around forever;  it plays nice with Apache through the mod_wsgi and mod_python libraries, and with Django a RoR-like development framework appeared.  It&#8217;s not as quite as &#8220;fun&#8221; to use as Ruby on Rails, but it more than makes up for it when I step in front of an executive committee that is extremely concerned about risk, long-term maintenance and stability of both the platform and community.</p>
<p>I&#8217;ve been dancing around Pinax for a few months.  Their philosophy that &#8220;there are a few different categories of web applications and they share similar basic functionality &#8211; which shouldn&#8217;t have to be written from scratch every time something needs to get done,&#8221; is congruent with my beliefs. While writing greenfield applications is a source of delight for competent engineers, it is preferable to build on a solid foundation of &#8220;super-libraries&#8221; and add the functionality that is needed for your particular requirements.<span id="more-1239"></span>Pinax offers this and so much more.  The developers of Pinax have created a set of &#8220;standard&#8221; platforms that may be used as an extendable base for anyone&#8217;s further development. The applications that they have created are:</p>
<ul>
<li><strong>sample_group_project:</strong> This project demonstrates group functionality with a barebones group?containing no extra content apps as well as two additional group types,?tribes and projects, which show different membership approaches and?content apps.</li>
</ul>
<ul>
<li><strong>intranet_project:</strong> This project demonstrates a closed site requiring an invitation to join and?not exposing any information publicly. It provides a top-level task tracking?system, wiki and bookmarks. It is intended to be the starting point of sites?like intranets.</li>
</ul>
<ul>
<li><strong>social_project:</strong> This project demonstrates a social networking site. It provides profiles,?friends, photos, blogs, tribes, wikis, tweets, bookmarks, swaps,?locations and user-to-user messaging.?<em>In 0.5 this was called &#8220;complete_project&#8221;.</em></li>
</ul>
<ul>
<li><strong>cms_project_holidayhouse:</strong> A very simple <a title="CMS" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');" href="http://en.wikipedia.org/wiki/Content_management_system">CMS</a> that lets you set up templates and then edit content, including images, right in the frontend of the site.?<em>The sample media, templates and content including in the project demonstrate?a basic site for holiday house rentals.</em></li>
</ul>
<ul>
<li><strong>code_project:</strong> This project demonstrates group functionality and the tasks, wiki and topics?apps. It is intended to be the starting point for things like code project?management where each code project gets its own wiki, task tracking system?and threaded discussions.</li>
</ul>
<ul>
<li><strong>private_beta_project:</strong> This project demonstrates the use of a waiting list and signup codes for?sites in private beta. Otherwise it is the same as basic_project.</li>
</ul>
<ul>
<li><strong>cms_project_company:</strong> A very simple CMS that lets you set up templates and then edit content,?including images, right in the frontend of the site.<em> The sample media, templates and content including in the project demonstrate?a basic company website.</em></li>
</ul>
<ul>
<li><strong>basic_project:</strong> This project comes with the bare minimum set of applications and templates?to get you started. It includes no extra tabs, only the profile and notices?tabs are included by default. From here you can add any extra functionality?and applications that you would like.</li>
<p><em>source &#8211; Pinax documentation</em></ul>
<p>These projects are all quite well developed even if they are not at a &#8220;1.0&#8243; release.  They all contain registration, email confirmation functionality, profile functionality and other basic &#8220;member&#8221; web application attributes.  I spent yesterday looking through the documentation and various on-line tutorials and deployed the sample_group_project on my Ubuntu 9.1-powered laptop.</p>
<p>I found that I had to jump between a couple of tutorials and once needed to completely wipe and rebuild to get it right, but the results were quite spectacular once I got it right.  Out of the box, user profiles, photo sharing, blogs, tweets, groups, Yahoo map locations, bookmarks and a &#8220;merchandise swapping and trading&#8221; application appear with no additional coding.  This application also enjoys Django&#8217;s dynamite Admin modules.</p>
<p>In a future post I&#8217;ll follow through and show what worked for me and endeavor to explain how easy it can be once you have everything in place.  As I develop the application, I&#8217;ll further post what I did to develop, deploy and extend the application for further use.</p>
<h3>Is it Ready for the Enterprise?</h3>
<p>I&#8217;m not sure if I can completely answer this question.  From an engineering/architecture point of view, it&#8217;s spot on.  For application maturity and production, that&#8217;s another matter.  Are there products using Pinax already?  What size are they?  Have they found, fixed and published bugs?</p>
<p>Quality Assurance in open-source projects can be in-bred amongst the developers and engineers on a project.  While they &#8220;know&#8221; the product the best and work to ensure functionality and eventual viability, they also make decisions on what needs to be fixed and &#8220;what can wait&#8221;.  In a strong enterprise environment, QA stands alone as a benevolent antagonist against development; business requirements will expose different issues and eventually make the product stronger.  If, as a technology leader, you are considering the use of Pinax, it would be prudent to add extra Quality Assurance time to the planned schedule to ensure future stability and a great customer experience.</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2010/03/05/looking-at-pinax-a-review/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu Karmic Koala &#8212; Buggy Laptop Touchpad Behavior in 9.1</title>
		<link>http://gurovich.com/site/2010/03/04/ubuntu-karmic-koala-buggy-laptop-touchpad-behavior-in-9-1/</link>
		<comments>http://gurovich.com/site/2010/03/04/ubuntu-karmic-koala-buggy-laptop-touchpad-behavior-in-9-1/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 15:32:20 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Dell laptop Ubuntu Koala touchpad]]></category>
		<category><![CDATA[Dell m90 ubuntu 9.10 touchpad]]></category>
		<category><![CDATA[Dell Precision Ubuntu Touchpad]]></category>
		<category><![CDATA[Linux touchpad Ubuntu problem]]></category>

		<guid isPermaLink="false">http://gurovich.com/site/?p=18</guid>
		<description><![CDATA[I recently upgraded my Dell Precision M90 Laptop to Ubuntu Karmic Koala. I&#8217;m running it standalone, no Windows anywhere. When I upgraded using ?apt-get upgrade? my touchpad didn?t work. Nothing. The touchpad was completely disabled. I assume that this is a problem on M70s, etc. Found a fix after searching for two days; ? in [...]]]></description>
			<content:encoded><![CDATA[<p>I recently upgraded my Dell Precision M90 Laptop to Ubuntu Karmic Koala. I&#8217;m running it standalone, no Windows anywhere. When I upgraded using ?apt-get upgrade? my touchpad didn?t work. Nothing. The touchpad was completely disabled. I assume that this is a problem on M70s, etc.</p>
<p>Found a fix after searching for two days; ? in case you&#8217;re having the same problem, here it is.<span id="more-18"></span></p>
<p>Open a terminal (if you don&#8217;t have a mouse hooked up, use Alt+F2). then &#8220;<em>su&#8221;</em> and give the root password (I tried doing this with?<em>sudo</em> and still didn&#8217;t have enough permission. I ? &#8220;think&#8221; you need to be root). At the prompt, type:</p>
<p><code>echo options psmouse proto=exps &gt; /etc/modprobe.d/psmouse.modprobe</code></p>
<p>At the next prompt, type:</p>
<p><code>reboot</code></p>
<p>Your touchpad will come back up after rebooting.</p>
<p><strong>Update 11/12/09</strong></p>
<p>I did an apt-get upgrade just after the release was announced.? ?It killed my NVidia driver and would boot up? ?once in awhile? in recovery mode.? ?I finally got frustrated and downloaded and burnt a DVD on my Mac, wiped the disk on my Dell and reinstalled the thing.? ?It?s working fine now; there is no bugginess in the touchpad, etc&#8230;</p>
<p>Ubuntu changed a lot of stuff in this release.? ?I find it almost similar to Mac?s move from OS9 to OSX, except that Mac ?warned us? that this was a big move.? ?Ubuntu rushed this release to coincide with Windows 7 and frankly they really dropped the ball on the message, the QA and the overall polish of the product.? ?Thank God I never trusted it enough to leave anything important on the Dell.? ?I?ve got Macs for the critical information over the house that are as stable as the Pyramids.? ?Snow Leopard was a? ?bug fix? release.? ?They?ve come a long way from the pre-Jaguar days, that?s for sure.? ?Ubuntu should take note.</p>
<p>Funny thing is, I actually like using the Ubuntu as much or more than the Mac, but then again, I like writing Python code in front of the TV with a cocktail!</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2010/03/04/ubuntu-karmic-koala-buggy-laptop-touchpad-behavior-in-9-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Test Driven Development &#8212; How to Start with a Test</title>
		<link>http://gurovich.com/site/2010/03/04/test-driven-development/</link>
		<comments>http://gurovich.com/site/2010/03/04/test-driven-development/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 14:33:44 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Enterprise Development]]></category>
		<category><![CDATA[Beginning Test Driven Development]]></category>
		<category><![CDATA[How to start with a test]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[TDD examples]]></category>
		<category><![CDATA[Test Driven Development]]></category>
		<category><![CDATA[Test Driven Development Example]]></category>
		<category><![CDATA[Test Driven Development Tutorial]]></category>

		<guid isPermaLink="false">http://gurovich.com/site/?p=8</guid>
		<description><![CDATA[Test Driven Development is mystical to any engineer that doesn&#8217;t have it as part of their development culture. ?Many shops don&#8217;t have the peer pressure and leadership that requires TDD in day-to-day operations. ?Others don&#8217;t see the need when working with Legacy Codebases. ?Some engineers have never written a unit test in their professional careers. [...]]]></description>
			<content:encoded><![CDATA[<p>Test Driven Development is mystical to any engineer that doesn&#8217;t have it as part of their development culture. ?Many shops don&#8217;t have the peer pressure and leadership that requires TDD in day-to-day operations. ?Others don&#8217;t see the need when working with Legacy Codebases. ?Some engineers have never written a unit test in their professional careers. ?No matter why Test Driven Development isn&#8217;t happening; once integrated into the engineering fabric of an organization, it will quickly take hold and spur productivity.</p>
<p>TDD is almost like riding a bike; you really don&#8217;t know how easy it is and how much fun you can have with it until you get up and going. When the training wheels are off, Test Driven Development (TDD) becomes a brand new world full of possibilities.<span id="more-8"></span></p>
<p>I have been writing unit tests for years, out of necessity to start, but later out of the desire to lead by positive example. Having come to the Computer Sciences later than most of my colleagues, I decided early on to adopt best practices to not only ensure that I wasn&#8217;t breaking builds, but I wanted to build the respect of my colleagues. Now, I really like to make sure that everything I commit to my various development communities are well-tested and as clean as possible.</p>
<p>Test Driven Development practices give me the verification necessary to check code in with confidence.? ?Unit testing builds this sense of security in three different ways:</p>
<ul>
<li>It guarantees that what I&#8217;ve written works, whether it&#8217;s new or integrated into existing platforms and applications.</li>
<li>It makes me keep my code simple. If I start writing a test and it becomes a dependency-driven, closely-coupled &#8220;implementation monster&#8221;, I can pretty much guarantee that the code is going to be the same. I&#8217;ll try to refactor this and use my tests in this manner as a guage for it&#8217;s quality.</li>
<li>In large environments that have continuous-build systems, there is always the inevitable &#8220;break&#8221; that stirs up panic and finger-pointing. Code with strong test coverage rarely breaks a build. This develops a team&#8217;s confidence in an individual&#8217;s engineering skills.</li>
</ul>
<p><em>So exactly HOW would I begin development by writing a test BEFORE I write any actual code, and WHY would I even want to?</em></p>
<p>We will address the &#8220;why&#8221; aspect first. &#8220;Old School&#8221; developers and my earliest mentors would create &#8220;fake&#8221; layers and tiers would test the code they were writing. A &#8220;fake layer&#8221; is defined as some type of data or code that simulates the functionality of an &#8220;expected&#8221; production-level deployment. Some development communities call these fake layers &#8220;tools&#8221; or &#8220;simulators&#8221;.</p>
<p>These ?fake layers? would be similar to tests, but these guys wouldn&#8217;t write tests because they never did in the past (and some still don?t!).? ?&#8221;Fake layers&#8221; can create all sorts of problems.? ?They tend to get passed around as API or Interface points, and as two different groups develop against these simulators, each makes compromises because they &#8220;must&#8221; integrate with the &#8220;tool&#8221;.? ?Testing just gives you a better framework for creating fake layers that you can create your code around.? ?It also creates a path of communication between development groups, negating the need for tools and promoting integration environments.</p>
<p><strong>HOW do you start with a test?</strong></p>
<p>Implementing your first Test Driven Development cycle is simple. Let?s say you will be writing an application that talks to a database that currently exists (you could even start without the database and just an ER diagram). Looking at your requirements, you are probably going to implement CRUD operations against it. You start thinking about what the interface for the Data Access Object is going to look like. ?<em>Hmmmm? ?Let?s see? CREATE, READ, UPDATE, DELETE</em>. So your simple Interface has four methods.</p>
<p>Now start with a test. Create a class called <em>MyDAOTestImpl</em>. <em>MyDAOTestImpl</em> will test the ?<strong><em>Implementation Class</em></strong> for the interface?s methods. When we create a method in the test that tests well, we then create the interface method, then the move the test method, with proper modifications, into the a new ?<em>MyDAOImpl</em> class. It makes you create very smart tests that ensure you are ?CRUD-ing? the data you expect. Coding in this way also creates the implementation to your interface at the simultaneously with the test. Finally, it makes you think about the interface and the implementation, and affects your overall design in a very positive light.</p>
<p>Now let?s take it further. You?ve created all the methods in your Impl class and your Interface methods can be extracted and the actual interface is now written and, for the time being, complete. Now let?s write a test that ?<em>calls</em> the Interface and implements a ?<em>new</em> Implementation Class through it. You can now see how clean your Interface is? &#8211;? how easy are your methods to use, how are things being cleaned up, and finally, how are exceptions being caught? Are you satisfied with the results so far? If so, proceed to the next layer!</p>
<p>The next layer may possibly involve a creating a Session Facade to allow for user interaction with the database (more complex implementations would have deeper structures). You may create an Object model that translates the Database relationships into some type of presentation-level object gouping, and write tests to reflect this. It becomes very obvious what objects you need when you start writing a test that outputs expected data a conditioned manner.</p>
<p>Your first cut at it may look like horrible code; it may be some type of monolithic monster, but it will give you clarity to understand how things must be split up. You keep refactoring and writing tests, and sooner rather than later, you are suprisingly code-complete, tight and ready for QA!</p>
<p><strong>Do what works for you.</strong></p>
<p>Even after all this I?m sure that some engineers are completely poo-pooing this way of developing applications. Many say that it&#8217;s writing &#8220;extra code&#8221;.? ?I dispute this.? ?Before writing so many tests, I wrote quite a bit of code and refactored it before it was checked in.? ?Sometimes I&#8217;d get caught up in a particularly cruel block of logic that would take hours to get to the bottom of, or worse I&#8217;d break somebody else&#8217;s logic block in another part of the application and it wouldn&#8217;t be found for a few days.? ?This was the worst case.? ?A set of unit tests would have found it in seconds, and it would take minutes to fix.? ?Concurrently, a set of tests to track the expected output of a logic block would have ensured that anything I&#8217;m stuck on can be worked through quickly.</p>
<p>Still not convinced?? ?That?s fine if it works for you.? ?TDD works for me.? ? I?ve found that as my tested code base and coverage build up, my productivity jumps dramatically as the project continues because I write less and less code as the project nears completion.</p>
<p>Test Driven Development is all about making everything solid. Using TDD, you?ll be writing one line of code to your previous ten, and when your ?business guy? walks in and asks for a change, you?ll be going home at 5 instead of having your car languish in the parking lot after midnight. You?ll also have more confidence in the quality of your check-ins and builds, and when things go wrong and the inevitable finger-pointing starts, you won?t be a <em>pointee</em>!</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2010/03/04/test-driven-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Simple &#8220;Restlet&#8221; Demo application</title>
		<link>http://gurovich.com/site/2009/11/23/a-simple-restlet-demo-application/</link>
		<comments>http://gurovich.com/site/2009/11/23/a-simple-restlet-demo-application/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 01:59:00 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Java Rest]]></category>
		<category><![CDATA[Restlet]]></category>
		<category><![CDATA[Restlet Demo]]></category>

		<guid isPermaLink="false">http://danilogurovich.wordpress.com/?p=106</guid>
		<description><![CDATA[I&#8217;m assuming that if you&#8217;re here you already know the basics of REpresentational State Transfer.  I&#8217;m also going to assume that you&#8217;ve looked at all the goodies at the Restlet community site.  Further, I&#8217;m thinking that you want a quick start guide to show you how to implement it.  The following tutorial shows how I [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m assuming that if you&#8217;re here you already know the basics of <strong>RE</strong>presentational <strong>S</strong>tate<strong> T</strong>ransfer.  I&#8217;m also going to assume that you&#8217;ve looked at all the goodies at the <a title="Restlet home pages" href="http://www.restlet.org" target="_blank">Restlet</a> community site.  Further, I&#8217;m thinking that you want a quick start guide to show you how to implement it.  The following tutorial shows how I &#8220;found a home&#8221; with Restlet, what worked for me, and hopefully something that will work for you, too.</p>
<p>The Restlet API is a Java framework for the REST architectural style. The <a href="http://www.restlet.org/documentation/1.1/nre/" target="_blank">Noelios Restlet Engine (NRE)</a> is available as the reference implementation, as well as <a href="http://www.restlet.org/documentation/1.1/ext/" target="_blank">several extensions</a> to the API and to NRE. <span id="more-106"></span></p>
<p><strong>Why is it cool?</strong></p>
<p>To Quote Jérôme Louvel, founder and lead developer of Restlet:</p>
<address>&#8220;After several iterations, it became clear that it would be beneficial for developers to separate the Restlet project into two parts. The first part is a generic set of classes, called the Restlet API, including a few helper classes and a mechanism to register a Restlet implementation. The second part is a reference implementation, called the Noelios Restlet Engine, including several server and client connectors (HTTP, JDBC, SMTP, etc.), a set of representations (based on strings, files, XML documents, templates, streams, etc.) and a Directory able to serve static files from a tree of directories with automatic content negotiation based on file extensions. Since the first public release in November 2005, the project keeps maturing thanks to the help of an active community of users and developers.&#8221;</address>
<p>It&#8217;s cool because it delivers on this statement.  I love that fact that you can send a request to a Restlet engine, and it will return back this amazing variety of Representations based upon it.  The first exposure to Restlet for me came when I put forth a design for a beacon tracking system that could be triggered via HTML pages, server-side calls, log-file digestion and anything else I could think of.  The lead developer turned me on to Restlet.</p>
<p>I later found ways to hook it up to a JBoss-Rules system, a Low-Latency Data Store for delivering customer demographic information, and a Affiliate Network lead quality validation system.  Each application had completely different requirements except that they needed to be a service.  I decided on REST instead of  SOAP, and the &#8220;rest&#8221; is in the implementations.  It subscribes to all my basic requirements for an application:</p>
<address> Any application that represents good design gives those that interact<br />
with it the feeling that &#8220;<strong>it just works&#8221;</strong>.</address>
<p>Once you work with Restlet a bit, get an application running, manipulate what you&#8217;ve built into other things, and get real expertise around it, you&#8217;ll find, like I have, that <em>it just works</em>.</p>
<h3>The Jars you need for this application.</h3>
<p>To run this application, you&#8217;ll need the following jar files:</p>
<ul>
<li>com.noelios.restlet.ext.servlet_2.5.jar</li>
<li>com.noelios.restlet.jar</li>
<li>org.restlet.jar</li>
<li>xalan-2.7.0.jar</li>
<li>xrcesImpl.jar</li>
</ul>
<div>This is the complete listing of libraries.</div>
<h3>Running Restlet from Tomcat &#8212; Configure the web.xml file.</h3>
<p>You&#8217;ll want to run Restlet from a WAR file in most production cases, but you really don&#8217;t have to.  I like to use it because it creates homogeneous environments for my ITOPs people to work with; nice, similar stacks for maintenance purposes, so we&#8217;ll do it this way here. It is my belief that productizing applications with little or no Network Configurations is key to long-term viability. The following is the web.xml file used in the web application that we&#8217;re deploying our service through:</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&gt;
    &lt;display-name&gt;first steps servlet&lt;/display-name&gt;
    &lt;!-- Application class name --&gt;
    &lt;context-param&gt;
        &lt;param-name&gt;org.restlet.application&lt;/param-name&gt;
        &lt;param-value&gt;
            <strong>com.dg.demo.restlet.application.DemoApplication</strong>
        &lt;/param-value&gt;
    &lt;/context-param&gt;

    &lt;!-- Restlet adapter --&gt;
    &lt;servlet&gt;
        &lt;servlet-name&gt;ServerServlet&lt;/servlet-name&gt;
        &lt;servlet-class&gt;
            com.noelios.restlet.ext.servlet.ServerServlet
        &lt;/servlet-class&gt;
    &lt;/servlet&gt;

    &lt;!-- Catch all requests --&gt;
    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;ServerServlet&lt;/servlet-name&gt;
        &lt;url-pattern&gt;/demo/*&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;
&lt;/web-app&gt;</pre>
<p>Note that com.dg.demo.restlet.application.DemoApplication will be the Application class file that you will write.  ServerServlet comes with the libraries.  Note that the &#8220;servlet-mapping&#8221; that I&#8217;m using here is &#8220;/demo/*&#8221;.  This means that all URLs directed to the Restlet must have &#8220;/demo/&#8221; as their root, (i.e. http://localhost:8080/demo/&#8230;).</p>
<p><strong>The Application Class</strong></p>
<p>The Application Class is the &#8220;manager&#8221; for the Restlet Application. This class will find the proper resource with respect to the URL that is presented to it.  In the case of this application, we&#8217;ll be mapping incoming URLs to:</p>
<ul>
<li>a &#8220;System up&#8221; Resource that shows that the Restlet is actually running and mapping correctly.</li>
<li>a &#8220;Mapping&#8221; Resource that will allow for a list of cities and states to be shown based upon given inputs.</li>
<li>an &#8220;XML&#8221; Resource that shows mappings of Cities and States as an XML Representation.</li>
</ul>
<p>Here is the application Class:</p>
<pre>package com.dg.demo.restlet.application;

import com.dg.demo.restlet.resource.CityXMLResource;
import com.dg.demo.restlet.resource.MapResource;
import com.dg.demo.restlet.resource.SystemResource;
import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.Router;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.StringRepresentation;

/**
 * The Application Root Class.  Maps all of the resources.
 */
public class DemoApplication extends Application {

    /**
     * Creates a new DemoApplication object.
     */
    public DemoApplication() {
        //empty
    }

    /**
     * Public Constructor to create an instance of DemoApplication.
     *
     * @param parentContext - the org.restlet.Context instance
     */
    public DemoApplication(Context parentContext) {
        super(parentContext);
    }

    /**
     * The Restlet instance that will call the correct resource
     * depending up on URL mapped to it.
     *
     * @return -- The resource Restlet mapped to the URL.
     */
    @Override
    public Restlet createRoot() {
        Router router = new Router(getContext());

        <strong>router.attach("/sys", SystemResource.class);
        router.attach("/{key}/maps", MapResource.class);
        router.attach("/xml", CityXMLResource.class);</strong>

        <strong>Restlet mainpage</strong> = new Restlet() {
            @Override
            public void handle(Request request, Response response) {
                StringBuilder stringBuilder = new StringBuilder();

                stringBuilder.append("&lt;html&gt;");
                stringBuilder.append("&lt;head&gt;&lt;title&gt;Sample Application " +
                        "Servlet Page&lt;/title&gt;&lt;/head&gt;");
                stringBuilder.append("&lt;body bgcolor=white&gt;");
                stringBuilder.append("&lt;table border=\"0\"&gt;");
                stringBuilder.append("&lt;tr&gt;");
                stringBuilder.append("&lt;td&gt;");
                stringBuilder.append("&lt;h3&gt;available REST calls&lt;/h3&gt;");
                stringBuilder.append("&lt;ol&gt;&lt;li&gt;/sys --&gt; returns system " +
                        "up and date string&lt;/li&gt;");
                stringBuilder.append("&lt;li&gt;/all/maps --&gt; returns a list" +
                        " of all the cities and states&lt;/li&gt;");
                stringBuilder.append("&lt;li&gt;/{key}/maps --&gt; returns a list " +
                        "of cities for a particular state (CA,IL,TX)&lt;br/&gt;");
                stringBuilder.append("using one of the keys from the \"all\" " +
                        "call&lt;br/&gt; pasted in place as the {key}.&lt;/li&gt;");
                stringBuilder.append("&lt;li&gt;/xml --&gt; POST or GET URL or web " +
                        "form elements as XML to this&lt;/li&gt;");
                stringBuilder.append("&lt;/ol&gt;");
                stringBuilder.append("&lt;/td&gt;");
                stringBuilder.append("&lt;/tr&gt;");
                stringBuilder.append("&lt;/table&gt;");
                stringBuilder.append("&lt;/body&gt;");
                stringBuilder.append("&lt;/html&gt;");

                response.setEntity(new StringRepresentation(
                        stringBuilder.toString(),
                        MediaType.TEXT_HTML));
            }
        };
        <strong>router.attach("", mainpage);</strong>
        return router;
    }
}</pre>
<p>With this Application I tried to show a &#8220;default&#8221;, &#8220;servlet-like&#8221; page returned by a Restlet created as an anonymous inner class &#8212; you can do that with all your URL requests if you like, but creating different Resource implementations is much easier to manage and write tests for. It is also very important to set the Context of the application in the Constructor (calling the superclass).  I forgot to do this and lost about an hour before I finally found it.</p>
<p>Once the Resources are mapped, You&#8217;re ready to rock and roll.  We&#8217;ll create a simple Model, and then get into the Resource Classes.</p>
<h3>A Simple Model to Work From:</h3>
<p>We need something to do with our application, so I decided to create a simple &#8220;persistence layer&#8221; that has a map of cities and states.  I could have done more and it could have been more complex, but I just wanted something that you can bang against and get an idea about how it all works.  I created an implementation class that contains a map of cities and states extending java.util.AbstractMap.  I then exposed various structures of this mapping through an interface class that the application will use to return information by implementing an Interface against it, obfuscating anything that I didn&#8217;t want to expose:</p>
<pre>package com.dg.demo.model;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A simple interface to return a map of
 * values for the demonstration.
 */
public interface MappedPersistence {

    // returns a formatted string of the cities
    // mapped to a particular state.
    String getCommonValues(String state);

    // returns a set of cities, which are
    // the map keys.
    Set&lt;String&gt; keys();

    // returns a map of cities &lt;K&gt; with states&lt;V&gt;
    // as the value.
    Map&lt;String, String&gt; proxy();

    // returns a set of states available.
    Set&lt;String&gt; valueSet();

    //returns a List of cities.
    List&lt;String&gt; mappedKeys(String s);

}</pre>
<p>The implementation of the Interface above is MappedCityPersistence:</p>
<pre>package com.dg.demo.model.impl;

import com.dg.demo.model.MappedPersistence;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Implementation of MappedPersistence Interface.
 * Extends Abstract Map, but obfuscates the
 * mappings via the MappedPersistence Interface.
 */
public class MappedCityPersistence
        extends AbstractMap&lt;String, String&gt;
        implements MappedPersistence {

    private Map&lt;String, String&gt; proxyMap;

    public MappedCityPersistence() {
        proxyMap = new HashMap&lt;String, String&gt;();
        loadProxy();
    }
    // this class must be implemented...
    public Set&lt;Entry&lt;String, String&gt;&gt; entrySet() {
        return proxyMap.entrySet();
    }
    //the values for persistence.
    private void loadProxy() {
        proxyMap.put("Los Angeles", "CA");
        proxyMap.put("Santa Barbara", "CA");
        proxyMap.put("San Francisco", "CA");
        proxyMap.put("San Diego", "CA");
        proxyMap.put("Dallas", "TX");
        proxyMap.put("Houston", "TX");
        proxyMap.put("Austin", "TX");
        proxyMap.put("El Paso", "TX");
        proxyMap.put("Chicago", "IL");
        proxyMap.put("Joliet", "IL");
        proxyMap.put("Naperville", "IL");
        proxyMap.put("Oak Park", "IL");
    }

    @Override
    public String toString() {
        StringBuilder builder =
                new StringBuilder("City/State values:\n");
        for (String s : proxyMap.keySet()) {
            builder.append(s).append(" =&gt; ")
                    .append(proxyMap.get(s)).append("\n");
        }
        return builder.toString();
    }

    public String getCommonValues(String value) {
        StringBuilder builder =
                new StringBuilder("Cities located in "
                        + value + ":\n");
        for (String s : proxyMap.keySet()) {
            if (proxyMap.get(s).equals(value)) {
                builder.append(s).append("\n");
            }
        }
        return builder.toString();
    }

    public Set&lt;String&gt; keys() {
        return proxyMap.keySet();
    }

    public Map&lt;String, String&gt; proxy() {
        return this.proxyMap;
    }

    public Set&lt;String&gt; valueSet() {
        Set&lt;String&gt; quickAndDirtySet = new HashSet&lt;String&gt;();
        for (String s : proxyMap.values()) {
            quickAndDirtySet.add(s);
        }
        return quickAndDirtySet;
    }

    public List&lt;String&gt; mappedKeys(String s) {
        List&lt;String&gt; quickAndDirtyList = new ArrayList&lt;String&gt;();
        for (String key : proxyMap.keySet()) {
            if (proxyMap.get(key).equals(s)) {
                quickAndDirtyList.add(key);
            }
        }
        return quickAndDirtyList;
    }

    public static void main(String[] args) {
        MappedCityPersistence p = new MappedCityPersistence();
        System.out.println(p.getCommonValues("TX"));
    }
}</pre>
<p>Note the extra methods that are now obfuscated by the Mapped Persistence Interface.</p>
<h3>Building the Resources that are Mapped to URLs</h3>
<p>The first, and easiest to implement of the Resources is the SystemResource that I created to show whether or not I got the mappings right and if the system is running or not.  It returns a basic &#8220;text&#8221; string that says the system is running and what time the JVM says it is:</p>
<p><strong>SystemResource.java</strong></p>
<pre>package com.dg.demo.restlet.resource;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;

import java.util.Calendar;

/**
 * Simple String retrieval to determine whether the system is up
 * and running.  it adds a timestamp for varification that the
 * message isn't cached and allows for identification of
 * the time zone.
 */
public class SystemResource extends Resource {

    /**
     * Creates a new MapResource object.
     *
     * @param context  -- Restlet Context Instance.
     * @param request  -- Restlet Request Instance.
     * @param response -- Restlet Response Instance.
     */
    public SystemResource(Context context,
                          Request request,
                          Response response) {
        super(context, request, response);
        // Here we add the representation variants exposed
        getVariants().add(new Variant(MediaType.TEXT_PLAIN));
    }

    /**
     * Do not allow post to this resource.
     *
     * @return -- always false for this resource.
     */
    public boolean allowPost() {
        return false;
    }

    /**
     * default method for "get" from Client Application.
     *  Returns wheter or not the system is available,
     * and the current time.
     *
     * @param variant -- Available variants.
     *
     * @return -- A String representing whether or
     *            not the demo system is available, etc.
     */
    public Representation represent(Variant variant) {
        //LQSCache.getInstance();
        <strong>String message = "hello!, the Demo " +
                "Service is available." +
                " Time of request is:"
                + Calendar.getInstance()
                .getTime().toString();</strong>

        return new StringRepresentation(message,
                MediaType.TEXT_PLAIN);
    }
}</pre>
<p>The mapping resource shows all of the cities and states mapped, and also shows the cities mapped to a particular state when that state is input within the url (i.e. http://localhost:8080/demo/all/maps &#8212; to show all cities and their city mappings, ./demo/TX/maps to get all cities mapped to Texas):</p>
<p><span><strong>MapResource.java</strong></span></p>
<pre>package com.dg.demo.restlet.resource;

import com.dg.demo.model.MappedPersistence;
import com.dg.demo.model.impl.MappedCityPersistence;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;

/**
 * Utility Resource to view the various strings
 * mapped in the Persistence.
 */
public class MapResource extends Resource {

    /**
     * The map requested by the client application
     */
    String mapName;

    /**
     * Creates a new MapResource object.
     *
     * @param context  -- The restlet Context instance.
     * @param request  -- The restlet REquest instance.
     * @param response -- The restlet Response instance.
     */
    public MapResource(Context context,
                       Request request,
                       Response response) {
        super(context, request, response);
        this.mapName = (String) request.getAttributes().get("key");

        // Here we add the representation variants exposed
        getVariants().add(new Variant(MediaType.TEXT_PLAIN));
    }

    /**
     * Do not allow post to this resource.
     *
     * @return -- always false for this resource.
     */
    @Override
    public boolean allowPost() {
        return false;
    }

    /**
     * Collect the values for a particular mapping and return
     * a formatted string.  By inputting "all" into the request,
     * it returns a list of the mappings available. When this
     * service returns, substituting "all" for one of the
     * returned values will return the values for that mapping key
     *
     * @param variant -- The variant describing the return mappings.
     *
     * @return -- a formatted string with the map values as a list.
     */
    @Override
    public Representation represent(Variant variant) {
        //UDCAPICache.getInstance();
        MappedPersistence persistence = new MappedCityPersistence();

        //LQSCache.getInstance();
        String message;
        //String mapName = (String) getRequest().getAttributes().get("key");

        if (mapName.equals("all")) {
            message = persistence.toString();
        } else if (persistence.valueSet().contains(mapName)) {
            message = persistence.getCommonValues(mapName);
        } else {
            message = "NO VALUES FOUND FOR: " + mapName;
        }
        return new StringRepresentation(message, MediaType.TEXT_PLAIN);
    }
}</pre>
<p>The XML resource returns a list of cities that are mapped to each state as an xml representation.  It allows a post or get, via the &#8220;acceptRepresentation()&#8221; (POST) and &#8220;represent()&#8221; (GET) methods.  I&#8217;ve put both of these in <strong>bold</strong>, along with other things that seemed important to me.  Each calls the same private method that creates the XML representation:</p>
<div><strong>CityXMLResource.java</strong></div>
<pre>package com.dg.demo.restlet.resource;

import com.dg.demo.model.MappedPersistence;
import com.dg.demo.model.impl.MappedCityPersistence;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.DomRepresentation;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.Variant;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.IOException;

public class CityXMLResource extends Resource {

    /**
     * @param context  -- Restlet Context Instance.
     * @param request  -- Restlet Request Instance.
     * @param response -- Restlet Response Instance.
     */
    public CityXMLResource(Context context,
                           Request request,
                           Response response) {
        super(context, request, response);
        getVariants().add(
                new Variant(MediaType.TEXT_PLAIN));
        getVariants().add(
                new Variant(MediaType.APPLICATION_XML));
        //handle(request,response);
    }

    /**
     * Flag to allow POST via web form.
     *
     * @return true if POST is allowed, false if not.
     */
    <strong>public boolean allowPost()</strong> {
        return true;
    }

    /**
     * Represent the requested object in the requested format.
     *
     * @param variant -- the requested variant or default.
     *
     * @return an XML representation or an error string.
     */
    <strong>public Representation represent</strong>(Variant variant) {
        DomRepresentation representation = null;
        try {
            representation = getFraudXMLRepresentation();
        } catch (IOException e) {
            e.printStackTrace();
            getResponse().setEntity("ERROR " + e.getMessage(),
                    MediaType.TEXT_PLAIN);
        }
        return representation;
    }

    /**
     * Handle a POST Http request.
     *
     * @param entity -- the declared entity
     */
    <strong>public void acceptRepresentation</strong>(Representation entity) {
        System.out.println("USING POST");

        try {
            if (entity.getMediaType()
                    .equals(MediaType.APPLICATION_WWW_FORM, true)) {
                DomRepresentation representation =
                        getFraudXMLRepresentation();
                // Returns the XML representation of this document.
                getResponse().setEntity(representation);
            }
        } catch (IOException e) {
            e.printStackTrace();
            getResponse().setEntity("ERROR " + e.getMessage(),
                    MediaType.TEXT_PLAIN);
        }
    }

    /**
     * Creates the XML that will be returned to the requesting client.
     *
     * @return - The formatted XML Document
     */
    private DomRepresentation getFraudXMLRepresentation() throws IOException {

        DomRepresentation representation =
                new DomRepresentation(MediaType.TEXT_XML);

        MappedPersistence persistence =
                new MappedCityPersistence();

        // Generate a DOM document representing the list of frauds generated..
        Document d = representation.getDocument();

        //The Root Element, with it's corresponding attribute for the total score.
        Element root = d.createElement("citystatemappings");
        root.setAttribute("numberofstates",
                String.valueOf(persistence.valueSet().size()));
        d.appendChild(root);

        //If there are no frauds, then we skip this and just return the root.
        for (String state : persistence.valueSet()) {
            Element stateElement = d.createElement("state");
            stateElement.setAttribute("name", state);

            for (String city : persistence.mappedKeys(state)) {
                Element cityElement = d.createElement("city");
                cityElement.appendChild(d.createTextNode(city));

                stateElement.appendChild(cityElement);
            }
            //tie the frauds to the root.
            root.appendChild(stateElement);
        }
        d.normalizeDocument();
        return representation;
    }
}</pre>
<p>Compile these classes into your web application with your lib jars, and make sure the &#8220;web.xml&#8221; file is configured as shown earlier in this text.  Create a .war file or run from your IDE.  You should be able to use the URLS that have been configured into the DemoApplication class file to view data in different formats.  If your application is configured to run on http://localhost:8080&#8230;</p>
<ul>
<li>http://localhost:8080/demo &#8212; returns the Representation defined in the &#8220;anonymous inner class&#8221; of the DemoApplication.</li>
</ul>
<ul>
<li>http://localhost:8080/demo/sys   &#8212; returns the &#8220;system up&#8221; resource and it&#8217;s information, something like:</li>
</ul>
<pre style="padding-left: 30px;">hello!, the Demo Service is available. Time of request is:Tue Sep 23 17:53:42 PDT 2008</pre>
<ul>
<li>http://localhost:8080/demo/all/maps &#8212; returns a list of all the states mapped into the persistence layer:</li>
</ul>
<pre style="padding-left: 30px;">City/State values:
Austin =&gt; TX
Chicago =&gt; IL
El Paso =&gt; TX
Los Angeles =&gt; CA
Naperville =&gt; IL
Houston =&gt; TX
San Diego =&gt; CA
Santa Barbara =&gt; CA
Dallas =&gt; TX
Oak Park =&gt; IL
Joliet =&gt; IL
San Francisco =&gt; CA</pre>
<ul>
<li>http://localhost:8080/TX/maps &#8212; returns a list of cities mapped to TX:</li>
</ul>
<pre style="padding-left: 30px;">Cities located in TX:
Austin
El Paso
Houston
Dallas</pre>
<p>http://localhost:8080/demo/xml &#8212; Finally, you want to get an xml representation of all this (view source):</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;citystatemappings numberofstates="3"&gt;
    &lt;state name="CA"&gt;
        &lt;city&gt;Los Angeles&lt;/city&gt;
        &lt;city&gt;San Diego&lt;/city&gt;
        &lt;city&gt;Santa Barbara&lt;/city&gt;
        &lt;city&gt;San Francisco&lt;/city&gt;
    &lt;/state&gt;
    &lt;state name="TX"&gt;
        &lt;city&gt;Austin&lt;/city&gt;
        &lt;city&gt;El Paso&lt;/city&gt;
        &lt;city&gt;Houston&lt;/city&gt;
        &lt;city&gt;Dallas&lt;/city&gt;
    &lt;/state&gt;
    &lt;state name="IL"&gt;
        &lt;city&gt;Chicago&lt;/city&gt;
        &lt;city&gt;Naperville&lt;/city&gt;
        &lt;city&gt;Oak Park&lt;/city&gt;
        &lt;city&gt;Joliet&lt;/city&gt;
    &lt;/state&gt;
&lt;/citystatemappings&gt;</pre>
<p>From here you&#8217;re on your own.  You should be able to extrapolate the tasks that you might need for your projects;  there are other representations that you can work with, including some very interesting uses of the java.util.nio libraries that allow for blazing fast file retrieval and delivery.  You can even send Java Objects around.  It&#8217;s worth looking through the<a title="Restlet API Documentation" href="http://www.restlet.org/documentation/1.1/api/" target="_blank"> Restlet API Docs at this point</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2009/11/23/a-simple-restlet-demo-application/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Object-Oriented JavaScript to Create Multi-Use Tabs</title>
		<link>http://gurovich.com/site/2008/08/10/using-object-oriented-javascript-to-create-multi-use-tabs/</link>
		<comments>http://gurovich.com/site/2008/08/10/using-object-oriented-javascript-to-create-multi-use-tabs/#comments</comments>
		<pubDate>Sun, 10 Aug 2008 22:16:51 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JavaScript Objects]]></category>
		<category><![CDATA[Object Oriented JavaScript]]></category>
		<category><![CDATA[Tabs in JavaScript]]></category>

		<guid isPermaLink="false">http://danilogurovich.wordpress.com/?p=79</guid>
		<description><![CDATA[Taking JavaScript More Seriously As I migrated from basic HTML to JSPs and finally complex Server-Side Java, I became less and less respectful of client-side languages, and most of my colleagues were pretty much in lockstep with me. While working in the view layer, adding JavaScript was a tedious necessity, and most programmers I worked [...]]]></description>
			<content:encoded><![CDATA[<h2>Taking JavaScript More Seriously</h2>
<p>As I migrated from basic HTML to JSPs and finally complex Server-Side Java, I became less and less respectful of client-side languages, and most of my colleagues were pretty much in lockstep with me. While working in the view layer, adding JavaScript was a tedious necessity, and most programmers I worked with built well-made, but <em>structural,</em> scripts to handle the needs of the page.  They knew what they wanted it to accomplish and they just wrote it to &#8220;do that thing&#8221;.  It &#8220;wasn&#8217;t worth&#8221; digging deep into it, because it is just &#8220;throw away&#8221; code that the view used; <em>not really worthy of Server-Side Programmers&#8217; attention</em>.<span id="more-79"></span></p>
<p>A new interest in JavaScript came onto my radar screen when, as a Principal Engineer at E*******k, I was presented with a problem that involved portal pages and their downloaded page weights. there were also many problems with any changes to the page breaking the very large (600 lines at one point) JavaScript that controlled much of the view layer. </p>
<p>So I looked into it.<!--more--></p>
<p>What I found was a gigantic script that controlled all sorts of things, looping through the Document Object Model, backwards and forwards; doing some <em>innerHTML</em> calls, and lots of &#8220;if this is happening&#8211; do this, disable this, and if anything ends in this, make it appear&#8221; kind of things.  It worked quite well, but nobody would dare change it, make changes to the basic UI or even allow it to be <em>touched</em>, because it was so complex and undocumented.  Resources were unavailble to keep up with it.</p>
<p>Being a Principal Engineer gave me the chance to take time and solve problems instead of doing hard core, heads-down coding every day.  I decided to take some time and crack this nut.  I started digging into a few articles about Object Oriented JavaScript and did a few exercises to really try and understand how it could work for me.  I discovered that with the page I was looking at, Tabs controlled a lot about what happened on it.  Depending upon which tab was clicked, different values would appear in the box underneath it &#8212; form fields would change, be disabled, etc.</p>
<p>Each Tab triggered a different &#8220;Mode&#8221; on the page.  So the Page has <em>Modes</em>&#8230; Well that would make a nice Object. The Mode has various attributes?  Now we&#8217;re getting somewhere!  Eventually this 600 line behemoth, tipping the scales at 86K, become a 64 line midget that, condensed, popped through the pipe at 16k.  Nice win.</p>
<p>What I&#8217;m demonstrating here isn&#8217;t this particular code. It <em>is</em> the basis for it, and not only that, I think its better than what I first wrote.  I&#8217;ve tested it on Mac Safari/Firefox &#8212; it should work on IE but I wasn&#8217;t able to test, so you might need to tweak.  So much for the disclaimer.</p>
<p><!--more--></p>
<h2>Creating a JavaScript Model to Manipulate Tabs on a Page</h2>
<p><em>code reference - </em><a title="Zipped content for initial tab functionality" href="http://www.gurovich.com/version_1_tabs.zip" target="_blank"><em>version_1_tabs.zip</em></a></p>
<p>Let&#8217;s start with the Initial Requirement.  Let&#8217;s say you have a requirement that orders 5 tabs that change back and forth with the least amount of scripting possible, and at some later date you might have to do more with it, such as add more tabs or add functionality to each tab.  To make it more complex, the Tab has images as background, so you need to manipulate these as well.</p>
<p>All the images will be manipulated through CSS, so we&#8217;re not going to clutter up <em>our beautiful HTML</em> markup with it.  Further, we&#8217;re going to not bother with &#8220;<em>document.write</em>&#8220;, because it can get kinda cluttered in the JavaScript code, I&#8217;m still not sure about performance hits using it, and you don&#8217;t get any Search Engine love with that, either.  Here below is the original HTML mark-up for the initial requirement (<em>tabpage.html</em>):</p>
<pre>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Object Oriented Tabs&lt;/title&gt;
    &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
    &lt;style type="text/css"&gt;
        @import url( "tabMode.css" );
    &lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;
&lt;table class="tabToggle" cellspacing="0"&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;span class="selectstring"&gt;Select Category&lt;/span&gt;&lt;/td&gt;
        &lt;td id="dramaTab"&gt;
            &lt;div&gt;
               &lt;a class="tab_0" href="#"
                           onclick="changeMode(DRAMA_MODE);return false;"&gt;
                &lt;span&gt;Drama&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="comedyTab"&gt;
            &lt;div&gt;
               &lt;a class="tab_1" href="#"
                           onclick="changeMode(COMEDY_MODE);return false;"&gt;
                &lt;span&gt;Comedy&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="thrillerTab"&gt;
            &lt;div&gt;
               &lt;a class="tab_2" href="#"
                           onclick="changeMode(THRILLER_MODE);return false;"&gt;
                &lt;span&gt;Thriller&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="mysteryTab"&gt;
            &lt;div&gt;
               &lt;a class="tab_3" href="#"
                           onclick="changeMode(MYSTERY_MODE);return false;"&gt;
                &lt;span&gt;Mystery&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="fantasyTab"&gt;
            &lt;div&gt;
               &lt;a class="tab_4" href="#"
                           onclick="changeMode(FANTASY_MODE);return false;"&gt;
                &lt;span&gt;Fantasy&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
    &lt;script type="text/javascript" src="tabtoggle.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>You will notice that for each href, there is an &#8220;<em>onclick</em>&#8221; value that is mapped to a <em>const</em> value (shown in the JavaScript file) in JavaScript.  For those of you that only code in IE, which doesn&#8217;t recognize <em>const</em>, it is exactly what you think.  an immutable value that is set and may not be changed.  Why is it cool?  because the browser maps it into memory, and it becomes a reference instead of a variable &#8212; <em>faster, like a static final value in Java</em>.  The other cool thing about it is that you can put any strings behind it, and if you&#8217;ve written your code properly, you only make a change in one place and can easily adapt your code to various conditions.  Easy to change, faster, and you&#8217;re not doing cut and paste everywhere.  Here is the JavaScript that manipulates the page (tabtoggle.js), with the constant values:</p>
<pre>/*------------- CONSTANTS -----------------------*/
//Mode names and values
const DRAMA_MODE = "drama";
const COMEDY_MODE = "comedy";
const THRILLER_MODE = "thriller";
const MYSTERY_MODE = "mystery";
const FANTASY_MODE = "fantasy";
//initial modes
const INIT_MODE = DRAMA_MODE;
// The array of Tabs -- establishes the order
// and values used. Pretty much the whole enchilada right here.
var TAB_ARRAY = [DRAMA_MODE,COMEDY_MODE,THRILLER_MODE,MYSTERY_MODE, FANTASY_MODE];

/*-------------MODEL--------------------------*/
/* This section could be separated from the
above as a "standard" library and used against
any set of tabs or arrays with an identical
structure.*/

//Local constants specific to the model.
const TAB_ID_SUFFIX = "Tab";
const EMPTY_STR = "";
// private Tab class values for CSS
const LAST_TAB_CLASS_VALUE = "last ";
const NON_SLCT_TAB_CLASS_VALUE = "engine";
const SLCT_TAB_CLASS_VALUE = " selected";

/**
 * The Class defining the Mode of the Object
 * @param name - The name of the Tab to that
 * will receive the selected state.
 */
function TabMode(name) {
    //public accessors
    this.name = tabModes(name);
    this.modeId = name + TAB_ID_SUFFIX;

    //change all the tabs, privately.
    function tabModes(name) {
        for (var i = 0; i &lt; TAB_ARRAY.length; i++) {
            var tid = TAB_ARRAY[i];
            var tab = new Tab(tid, (name == tid), (i == (TAB_ARRAY.length - 1)));
            document.getElementById(tab.tabId).className = tab.classVal;
        }
        return name;
    }
}

/**
 * A Tab object with needed attributes.
 * @param id -- mapped to the "id" attribute of the HTML.
 * @param selected -- boolean as to whether or not it
 * is in a "selected" state.
 * @param isLast -- boolean as to whether or not it
 * is the last tab of the series.
 */
function Tab(id, selected, isLast) {
    //accessors
    this.tabId = id + TAB_ID_SUFFIX;
    this.classVal = selectCheck();

    function selectCheck() {
        var cval = NON_SLCT_TAB_CLASS_VALUE;
        if (selected) {
            cval += SLCT_TAB_CLASS_VALUE;
        }
        if (isLast) {
            cval = LAST_TAB_CLASS_VALUE + cval;
        }
        return cval;
    }
}

/*------------- page-accessible methods -----------------------*/

//initialize mode object
var mode;

/**
 * "Public" function to change the name of the tab.
 * Accepts any tabname value mapped to the above constants.
 * @param tabname - a legal value within the TAB_ARRAY.
 */
function changeMode(tabname) {
    mode = new TabMode(tabname);
}

/**
 * Load up the initial mode.  Initializes what is
 * Shown on the page first.
 */
changeMode(INIT_MODE);</pre>
<p>Ok, it&#8217;s more than 64 lines.  Production versions of this might have the comments stripped and some compression. It currently weighs in at 4k. The constants at the top of the file are:</p>
<pre>//Mode names and values
const DRAMA_MODE = "drama";
const COMEDY_MODE = "comedy";
const THRILLER_MODE = "thriller";
const MYSTERY_MODE = "mystery";
const FANTASY_MODE = "fantasy";</pre>
<p>These are mapped to the tabs, but the tabs all have a &#8220;<em>Tab</em>&#8221; string-value appended to it in the &#8220;<em>id</em>&#8221; attribute.  We&#8217;ll use this to manipulate the view elements (usually in CSS) by the &#8220;getElementByID&#8221; method.  There are two objects that are created in the JavaScript file; one is Tab, and the other is TabMode. </p>
<h3><strong>What I&#8217;m doing here &#8212; the basics of declaring Objects in JavaScript</strong></h3>
<p>To declare an Object in JavaScript, create a function, and for best practices-sake, use an initial capital letter, similar to a Java Class Declaration.  Since we&#8217;re not dealing with a pure object-oriented language, we&#8217;ll need to declare our Object as a function:</p>
<pre>function Tab(id, selected, isLast) {</pre>
<p>and</p>
<pre>function TabMode(name) {</pre>
<p>There&#8217;s no constructor method in the class.  The function declaration contains the attributes needed to construct the Object.  <em>Tab</em> take three attributes &#8212; the id, a boolean for &#8220;selected&#8221;, and a boolean for &#8220;isLast&#8221; to delinieate whether or not it is the last Tab in the sequence.  You can use an Object quite easily, so let&#8217;s create some basic <em>FooObject</em> and demonstrate a few things.  Here&#8217;s an Object assigned to a variable:</p>
<pre><em>var foo = new FooObject("funky","fruity");</em></pre>
<p>This object instance can now be accessed by using <em>foo</em>.  What are &#8220;funky&#8221; and &#8220;fruity&#8221;?  How do we associate these to <em>FooObject</em>?</p>
<p>They have been used in the &#8220;constructor&#8221; to the Object.  The inner methods of the Object will use this information to populate accessors and can even be injected into private functions.  Let&#8217;s take a look at the actual FooObject declaration, and create some basic accessors for it:</p>
<pre>function FooObject(smell, taste){
          this.smell = smell;
          this.taste = taste;
}</pre>
<p>So, using the foo variable from the earlier listing, <em>foo.smell</em> would return &#8220;funky&#8221;, and <em>foo.taste</em> returns &#8220;fruity&#8221;.  Go ahead and try it, it&#8217;s just that easy. </p>
<h3>The Tab Object</h3>
<p>Now back to the <em>tabtoggle.js</em> code. Besides accessors, I added some private functions to return some values.  The reason I made them private as I didn&#8217;t want some <em>hackmeister</em> coming in behind me and using these functions outside of the Object, creeping everything out on my page.  Here is the &#8220;Tab&#8221; Object code snip for discussion purposes:</p>
<pre>function Tab(id, selected, isLast) {
    //accessors
    this.tabId = id + TAB_ID_SUFFIX;
    this.classVal = selectCheck();

    function selectCheck() {
        var cval = NON_SLCT_TAB_CLASS_VALUE;
        if (selected) {
            cval += SLCT_TAB_CLASS_VALUE;
        }
        if (isLast) {
            cval = LAST_TAB_CLASS_VALUE + cval;
        }
        return cval;
    }
}</pre>
<p>There are two accessors in the Tab Object, created from the three parameters and some of the &#8220;constants&#8221; that were declared outside of the class and available to the entire Document. The first accessor is the &#8220;id&#8221; used for the tab, and the second is used to build a CSS class value to alter the corresponding Tab&#8217;s view.  </p>
<p>This second accessor, &#8220;classVal&#8221;, is interesting because it is mapped to an inner function that determines its actual value.  This function could be mapped externally to the Tab, and I&#8217;ve done this before, but after some deliberation, I decided to keep it private because I didn&#8217;t want to make it available outside of the Object.</p>
<h3>The TabMode Object</h3>
<p>The TabMode Object defines the Mode of the each tab.  It takes a &#8220;name&#8221; parameter that iterates through the TAB_ARRAY (Ordered Array of all Tabs) and creates Tab Objects and sets their class value through the <em>document.getElementById() </em>method.  I &#8220;cheated&#8221; a little here by calling this method while I set the Tab instances-  mainly to ensure that the iteration was complete (it would throw errors at this point if there is a failure).  I highlighted in red the real work that&#8217;s getting done.</p>
<pre>/**
 * The Class defining the Mode of he Object
 * @param name - The name of the Tab to that
 * will receive the selected state.
 */
function TabMode(name) {
    //public accessors
    this.name = <span style="color:#ff0000;">t</span><span style="color:#ff0000;">abModes(name)</span>;
    this.modeId = name + TAB_ID_SUFFIX;

    //change all the tabs, privately.
    function tabModes(name) {
        for (var i = 0; i &lt; TAB_ARRAY.length; i++) {
            <span style="color:#ff0000;">var tid = TAB_ARRAY[i];
            var tab = new Tab(tid, (name == tid), (i == (TAB_ARRAY.length - 1)));
            document.getElementById(tab.tabId).className = tab.classVal;</span>
        }
        return name;
    }
}</pre>
<p>Everything will work now.  Go ahead and open up the HTML page and click on the  tabs.  We have a very nice and snappy set of tabs with only a little bit of code.  We can change the code in different ways to make it more useful.  In the next two sections, I&#8217;ll demonstrate how to use the basic JavaScript file that we&#8217;ve already defined against a completely different set of tabs with minimal code change, and then in the last section I&#8217;ll add more functionality to show/hide different information boxes when a particular tab is clicked.</p>
<p><!--more--></p>
<h2>Using the Same Basic Code to Populate Different Tabbed Pages</h2>
<p><em>code reference &#8211; <a title="Zipped content for extended tab functionality" href="http://www.gurovich.com/version_2_tabs.zip" target="_blank">version_2_tabs.zip</a></em></p>
<p>We&#8217;re now going to take the code that we just wrote, create another HTML page with the same functionality but completely different tabs using the same structure, only changing the &#8220;name&#8221; constants and the &#8220;array&#8221; that they are located in.</p>
<p>The only big change is to separate &#8220;Page Attributes&#8221; that define a particular page for the &#8220;Model&#8221; part of the JavaScript Code.  There is no real dependency between them, and as long as there are &#8220;names&#8221; and an &#8220;array&#8221; to traverse, the tabs will pretty much work as designed against anything you want.  This allows for any number of different tabs or tab names to be used &#8212; you just attach a new file with the constants you want to use for the page, and plug in the same JavaScript Toggle Model.  For this particular exercise, we created a file that only holds the constants that we want to use for the first &#8220;tabpage1.html&#8221;.</p>
<pre>const DRAMA_MODE = "drama";
const COMEDY_MODE = "comedy";
const THRILLER_MODE = "thriller";
const MYSTERY_MODE = "mystery";
const FANTASY_MODE = "fantasy";
//initial modes
const INIT_MODE = DRAMA_MODE;
// The array of Tabs -- establishes the order
// and values used. Pretty much the whole enchilada right here.
var TAB_ARRAY = [DRAMA_MODE,COMEDY_MODE,THRILLER_MODE,
                 MYSTERY_MODE, FANTASY_MODE];

// private Tab class values for CSS
const LAST_TAB_CLASS_VALUE = "last ";
const NON_SLCT_TAB_CLASS_VALUE = "engine";
const SLCT_TAB_CLASS_VALUE = " selected";</pre>
<p>No structural code changes were made.  I just &#8220;cut&#8221; the script from the first section in two, putting the constants that are mutable away from all of the code that doesn&#8217;t need to change.  If we want to create a different page, we&#8217;ll be able to use the exact same &#8220;model&#8221; code and only change the code in the listing above to suit our needs.  The Model part of the code is still located in the &#8220;tabtoggle.js&#8221; file. </p>
<p>Since there&#8217;s no change, I&#8217;ve truncated the listing below only to provide clarity as to where the &#8220;split&#8221; occurs.  refer to the <a title="Zipped content for extended tab functionality" href="http://www.gurovich.com/version_2_tabs.zip" target="_blank">version_2_tabs.zip</a> for more granularity.</p>
<pre>/*-------------MODEL--------------------------*/

//Local constants specific to the model.
const TAB_ID_SUFFIX = "Tab";
const EMPTY_STR = "";

function TabMode(name) {
  ... (no changes to code -- see details in zipped download)
}

function Tab(id, selected, isLast) {

... (no changes to code -- see details in zipped download)}

/*-------- page-accessible methods -----------*/

//initialize mode object
var mode;

function changeMode(tabname) {
    mode = new TabMode(tabname);
}

changeMode(INIT_MODE);</pre>
<p>Again, no changes.  We&#8217;ve left the &#8220;model&#8221; part of the code at the bottom of the page to load just before the &lt;/body&gt; tag, and the &#8220;Page Attributes&#8221; are coded to load in the &lt;head&gt; of the document.  Other than that, the HTML is unchanged in the &#8220;tabpage1.html&#8221;.  The tabs will work and fire identically as they did before.</p>
<p>But now, we get to do something cool.  We create a new HTML file, &#8220;tabpage2.html&#8221;, and put completely different tab names in them.  Not only are they different names, they are even more of them!  The underlying model code will handle them perfectly, as all it cares about is the array mapped to the constant names.  The array provides the order and a looping mechanism, and the constants provide a way to change things without making changes all over the place.</p>
<p>The new HTML code contains different cartoon shows or characters mapped to the same html pattern as &#8220;tabpage1.html&#8221;.  Here is the new table with the tabs.  Changes are in <span style="color:#ff0000;">red</span>:</p>
<pre>&lt;/head&gt;
&lt;body&gt;
&lt;table class="tabToggle" cellspacing="0"&gt;
    &lt;tr&gt;
       <span style="color:#ff0000;"><strong> &lt;td&gt;&lt;span class="selectstring"&gt;Select Category&lt;/span&gt;&lt;/td&gt;
        &lt;td id="bullwinkleTab"&gt;
            &lt;div&gt;&lt;a class="tab_0" href="#" onclick="changeMode(BULLWINKLE_MODE);return false;"&gt;
                &lt;span&gt;Bullwinkle&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="tomandjerryTab"&gt;
            &lt;div&gt;&lt;a class="tab_1" href="#" onclick="changeMode(TOM_AND_JERRY_MODE);return false;"&gt;
                &lt;span&gt;Tom and Jerry&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="simpsonsTab"&gt;
            &lt;div&gt;&lt;a class="tab_2" href="#" onclick="changeMode(SIMPSONS_MODE);return false;"&gt;
                &lt;span&gt;Simpsons&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="futuramaTab"&gt;
            &lt;div&gt;&lt;a class="tab_3" href="#" onclick="changeMode(FUTURAMA_MODE);return false;"&gt;
                &lt;span&gt;Futurama&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="bugsbunnyTab"&gt;
            &lt;div&gt;&lt;a class="tab_4" href="#" onclick="changeMode(BUGSBUNNY_MODE);return false;"&gt;
                &lt;span&gt;Bugs Bunny&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="mickeymouseTab"&gt;
            &lt;div&gt;&lt;a class="tab_5" href="#" onclick="changeMode(MICKEYMOUSE_MODE);return false;"&gt;
                &lt;span&gt;Mickey Mouse&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="barneybearTab"&gt;
            &lt;div&gt;&lt;a class="tab_6" href="#" onclick="changeMode(BARNEYBEAR_MODE);return false;"&gt;
                &lt;span&gt;Barney Bear&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
        &lt;td id="ScoobyDooTab"&gt;
            &lt;div&gt;&lt;a class="tab_7" href="#" onclick="changeMode(SCOOBYDOO_MODE);return false;"&gt;
                &lt;span&gt;Scooby Doo&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;</strong></span>
    &lt;/tr&gt;
&lt;/table&gt;
&lt;script type="text/javascript" src="tabtoggle.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Note the script reference at the bottom of the page.  It only contains the &#8220;Model&#8221; code.  The new &#8220;Page Attributes&#8221; are shown below, contained in the file tabpage2.js.  New code is in <span style="color:#ff0000;">red</span>.  Although there is some &#8220;cut and paste&#8221; code in here, it&#8217;s because we might want to change the class names of the tabs to vary the view, and this would be the best place to keep it.:</p>
<pre>/*
 * Copyright (c) 2008, Your Corporation. All Rights Reserved.
 */
/*------------- CONSTANTS -----------------------*/
//Mode names and values
<strong><span style="color:#ff0000;">const BULLWINKLE_MODE = "bullwinkle";
const TOM_AND_JERRY_MODE = "tomandjerry";
const SIMPSONS_MODE = "simpsons";
const FUTURAMA_MODE = "futurama";
const BUGSBUNNY_MODE = "bugsbunny";
const MICKEYMOUSE_MODE = "mickeymouse";
const BARNEYBEAR_MODE = "barneybear";
const SCOOBYDOO_MODE = "ScoobyDoo";</span></strong>
//initial modes
const INIT_MODE = <strong><span style="color:#ff0000;">BULLWINKLE_MODE</span></strong>;
// The array of Tabs -- establishes the order
// and values used. Pretty much the whole enchilada right here.
var TAB_ARRAY = <strong><span style="color:#ff0000;">[BULLWINKLE_MODE,
    TOM_AND_JERRY_MODE,SIMPSONS_MODE,FUTURAMA_MODE,
    BUGSBUNNY_MODE,MICKEYMOUSE_MODE,BARNEYBEAR_MODE,
    SCOOBYDOO_MODE];</span></strong>

// private Tab class values for CSS
const LAST_TAB_CLASS_VALUE = "last ";
const NON_SLCT_TAB_CLASS_VALUE = "engine";
const SLCT_TAB_CLASS_VALUE = " selected";</pre>
<p>When you load the the &#8220;tabpage2.html&#8221; in the browser, the new tabs will appear, with new names, more of them, but with exactly the same functionality. The underlying model works just as it did with the tabs on the other page, with only the inputs changed. You could put the inputs on the page or load it into a file that is picked up by the page as we did here  I believe either is fine &#8211; your decision where to put them is based upon your requirements and judgement.  No wrong answers!</p>
<h2><!--more-->Adding A Content Box Below the Tabs</h2>
<p><em>code reference &#8212; <a title="Zipped content for tabbed content and boxes" href="http://www.gurovich.com/version_3_tabs.zip" target="_blank">version_3_tabs.zip</a></em></p>
<p>Finally, we get a requirement to load a different but corresponding content box to the tabs we have created.  Let&#8217;s also say that our requirement states that only some of the tabs will have variable content boxes, other functionality may be required elsewhere.  We want to add a c<em>ontent show-hide</em> feature to the boxes, yet make sure that any tabbed page using our code doesn&#8217;t throw errors, <em>as we just hate that</em>.   The style attribute we will chose is &#8220;<em>visiblity</em>&#8220;, and we&#8217;ll use the &#8220;<em>none</em>&#8221; and &#8220;<em>inline</em>&#8221; values &#8212; since &#8220;<em>none</em>&#8221; will take the object out of formatting and not affect the flow of the page. &#8220;<em>inline</em>&#8221; will put the box in the flow. To change the style attribute trigger, we&#8217;ll use:</p>
<pre>document.getElementById("foo").style.display = ...</pre>
<p>It is necessary to loop through all of the tabs whenever the page mode is changed to make sure that the right one is &#8220;turned on&#8221; and the others are invisible.  Arriving at this functionality is actually quite easy.  We&#8217;ll just add this to the existing private function in the <em>TabMode</em> Object.</p>
<p>A new HTML page is similar to the others we&#8217;ve created, with the changes added in the listing below (changes in <span style="color:#ff0000;">red</span>, surrounded by existing code for reference).  The &#8220;outer&#8221; <em>div</em> for each box is what controls the visibility, the &#8220;inner&#8221; <em>div</em> with the <em>class</em> attribute &#8220;<em>underbox</em>&#8221; is for decorating the view, and has the <em>class</em> value mapped into the css file to control it.  Each &#8220;<em>id</em>&#8221; attribute in the &#8220;outer&#8221; box maps to a tab &#8220;<em>name</em>&#8221; attribute, the &#8220;<em>Box</em>&#8221; is the suffix for this <em>id</em> and is used within the JavaScript code, e.g. dramaBox, comedyBox, etc.</p>
<pre>       &lt;td id="fantasyTab"&gt;
            &lt;div&gt;&lt;a class="tab_4" href="#" onclick="changeMode(FANTASY_MODE);return false;"&gt;
                &lt;span&gt;Fantasy&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
<strong><span style="color:#ff0000;">&lt;!-- Add a Box! --&gt;
&lt;div id="dramaBox"&gt;
    &lt;div class="underbox"&gt;
        &lt;h2&gt;Drama&lt;/h2&gt;
        Lorem ipsum dolor sit amet,...
        zzril delenit augue duis dolore te feugait
        nulla facilisi.
    &lt;/div&gt;
&lt;/div&gt;
&lt;div id="comedyBox"&gt;
    &lt;div class="underbox"&gt;
        &lt;h2&gt;Comedy&lt;/h2&gt;
        Darkness washed over the Dude, darker than a steer's
        tukus on a moonless night.
    &lt;/div&gt;
&lt;/div&gt;
&lt;div id="thrillerBox"&gt;
    &lt;div class="underbox"&gt;
        &lt;h2&gt;Thriller&lt;/h2&gt;
        ... So I made a decision, and it
        was... wrong. It was a bad call, Ripley. It was a bad call..
    &lt;/div&gt;
&lt;/div&gt;
&lt;div id="mysteryBox"&gt;
    &lt;div class="underbox"&gt;
        &lt;h2&gt;Mystery&lt;/h2&gt;
        Some text here
    &lt;/div&gt;
&lt;/div&gt;
&lt;div id="fantasyBox"&gt;
    &lt;div class="underbox"&gt;
        &lt;h2&gt;Fantasy&lt;/h2&gt;
        Some text here...
    &lt;/div&gt;
&lt;/div&gt;</span></strong>
&lt;script type="text/javascript" src="tabtoggle.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Here is the code for the enhanced tabs in the file<em> tabtoggle.js</em>. The only change needed is to add a few constants and a small conditional routine in the <em>TabMode</em> Object.  It will actually detect if the boxes are present to toggle their visibility, otherwise this functionality is ignored. The changed code is in <span style="color:#ff0000;">red</span>.</p>
<pre><span style="color:#ff0000;"><strong>const BOX_ID_SUFFIX = "Box";</strong></span>
//Display box values
<strong><span style="color:#ff0000;">const YES_DISPLAY = "inline";
const NO_DISPLAY = "none";</span></strong>

/**
 * The Class defining the Mode of he Object. Alters the tab Selected,
 * and also changes which box should be displayed under it, IF a box exists.
 * @param name - The name of the Tab to that
 * will receive the selected state.
 */
function TabMode(name) {
    //public accessors
    this.name = tabModes(name);
    this.modeId = name + TAB_ID_SUFFIX;

    //change all the tabs, privately.
    function tabModes(name) {
        for (var i = 0; i &lt; TAB_ARRAY.length; i++) {
            var tid = TAB_ARRAY[i];
            var tab = new Tab(tid, (name == tid), (i == (TAB_ARRAY.length - 1)));
            document.getElementById(tab.tabId).className = tab.classVal;
        }
        //This changes out the boxes, if they exist...
        <strong><span style="color:#ff0000;">if (document.getElementById(name + BOX_ID_SUFFIX) != null) {
            for (var i = 0; i &lt; TAB_ARRAY.length; i++) {
                var tid = TAB_ARRAY[i];
                if (tid == name) {
      document.getElementById(tid+ BOX_ID_SUFFIX).style.display = YES_DISPLAY;
                } else {
      document.getElementById(tid+ BOX_ID_SUFFIX).style.display = NO_DISPLAY;
                }
            }</span></strong>
        }
        return name;
    }
}</pre>
<p>The code above will now allow the choosing of each tab and the display of different boxes below.  Not only that, but when applied to our second, &#8220;cartoon tabs&#8221;, page, no errors will be thrown since there is a &#8220;check&#8221; as to whether the boxes exist first.  If you want to add boxes to the other page, you just map them to their tab names and use the &#8220;Box&#8221; instead of &#8220;Tab&#8221; suffix!</p>
<h2>Conclusions:</h2>
<p>Using the JavaScript Prototype element can extend the above code in even more directions.  Want to have a form connected to each tab?  Do they have different elements?  You can enable and disable them by extending the above classes to do even more.  A &#8220;TabbedForm&#8221; class could contain the form elements and keep track of what to enable and disable, different submission urls or even more.  You don&#8217;t have to alter the base class, you just extend it using the Prototype Element.</p>
<p>One of the truly wonderful things about JavaScript is the fact that there are many ways to the same result.  What I find interesting is how people can come up with ideas to make their scripts smaller, more re-usable and extendable.  Creating Objects in JavaScript allow for power that many mark-up engineers don&#8217;t know about to this day;  a lot of server-side programmers, myself included, begin to take this client side language seriously and realize the power, and fun, of writing this type of code.</p>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2008/08/10/using-object-oriented-javascript-to-create-multi-use-tabs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Overlapping Schedule Process for Maintenance and Enhancement of Complex Web Properties</title>
		<link>http://gurovich.com/site/2008/07/22/the-overlapping-schedule-process-for-maintenance-and-enhancement-of-complex-web-properties/</link>
		<comments>http://gurovich.com/site/2008/07/22/the-overlapping-schedule-process-for-maintenance-and-enhancement-of-complex-web-properties/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 02:09:48 +0000</pubDate>
		<dc:creator>Danilo Gurovich</dc:creator>
				<category><![CDATA[Dev process]]></category>
		<category><![CDATA[Enterprise Development]]></category>
		<category><![CDATA[Development Processes]]></category>
		<category><![CDATA[eCommerce Development Processes]]></category>
		<category><![CDATA[eCommerce Process]]></category>
		<category><![CDATA[JIRA]]></category>
		<category><![CDATA[Overlapping Schedule Model]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://danilogurovich.wordpress.com/?p=56</guid>
		<description><![CDATA[Building a Consistent, Predictable and Efficient Environment for Enterprise eCommerce Applications.   Predictable Schedules Create Outstanding Teams When many eCommerce shops first set up, there are usually a few developers wearing many hats; they have access to everything, develop within specific areas and channels, and check in code for deployment as it becomes ready. While [...]]]></description>
			<content:encoded><![CDATA[<p><em><span style="font-weight:normal;">Building a Consistent, Predictable and Efficient Environment for Enterprise eCommerce Applications.</span></em><br />
 </p>
<h2>Predictable Schedules Create Outstanding Teams</h2>
<p>When many eCommerce shops first set up, there are usually a few developers wearing many hats; they have access to everything, develop within specific areas and channels, and check in code for deployment as it becomes ready.  While this type of development will work as a business starts, it will soon become unmanageable and will result undesired consequences as changes are not integrated, and business priorities are not addressed, or worse.</p>
<p>Predictability and easily enforced processes set all stakeholders within an application free to do their jobs and collaborate at the highest levels possible.  With a strong process, planned changes will be scheduled for deployment with a high degree of accuracy.  Engineers enjoy complete and accurate requirements, and know what is expected of them throughout each cycle.  Quality Assurance will have time to create plans and fully test changes, and Releases to Production will no longer be a nail-biting, all-hands-on-deck stress-fest.</p>
<p>The following proposed process details the steps necessary for day-to-day development, maintenance and enhancements for the IHO/Offer Channels applications.  They are exclusive of longer-term enhancements and development requiring multiple-week pulls.  Only those issues that may be completed in short periods will applies here,.  This is significant because with most mature applications, nearly 75% of all issues encompass this type of development.</p>
<h3>Tracking the status of Issues</h3>
<p>An Issue Tracking System is a “blog-like” application that allows issues to be tracked throughout the development/release cycle.  Its main features include fields to track:<span id="more-73"></span></p>
<ul>
<li>Who the Business Stakeholder is for the issue (i.e. owner)</li>
<li>Who has responsibility for the Issue’s forward progress at a point in time</li>
<li>The Scheduled Release Date</li>
<li>An identifier for the issue so that communication may occur around it</li>
<li>A field to delinieate the Issue’s status</li>
<li>Attachments to the Issue for requirements or any information needed to proceed in the process</li>
<li>A &#8220;Comments&#8221; section that allows all stakeholders to create a chronological and permanent record of what happened to the issue over its lifecycle</li>
</ul>
<p>Other features of a robust issue tracking system are excellent aggregation and reporting tools, integration with Wiki pages, email notifications and IDE integration.  The tool chosen by many, and arguably a “best of breed” is <a title="Atlassian's JIRA software" href="http://www.atlassian.com" target="_blank">“JIRA” from Atlassian Software</a>.</p>
<h3>Assumptions</h3>
<p>Many, if not most, of the web applications built in an enterprise are ongoing products that require maintenance, small tweaks and enhancements on an ongoing basis.  While larger changes to the system occur on a much more infrequent basis, it is essential that these be separated out into a different schedule and allow for the ongoing implementations to occur on a regular schedule that has no dependencies upon larger, more complex deployments.</p>
<p>There are several assumptions that must be made to completely embrace the Overlapping Schedule Model fully:</p>
<ol>
<li>There will always be more issues and tweaks needed than resources available</li>
<li>A method for communicating issues between all stakeholders exists</li>
<li>There is a need for predictability and pacing</li>
<li>While not perfect, the application has some stability</li>
</ol>
<h2>The <em>Overlapping Schedule</em> Model</h2>
<p>An Overlapping Schedule is a very efficient model to keep the all business process stakeholders fully engaged, collaborative and running at peak efficiency.  It uses tight structure to coordinate activities in three separate areas, Business, Development, and Release/QA. While Business Stakeholders are planning future releases, the Engineering Team is developing the next release, and the QA and Release Management is readying/deploying the current release for production.</p>
<p>Figure 1 shows the basic development cycle and it’s overlapping steps, creating a never-ending, continuous process that keeps all resources utilized at maximum efficiency:</p>
<p> </p>
<div id="attachment_58" class="wp-caption aligncenter" style="width: 437px"><a href="http://danilogurovich.files.wordpress.com/2008/07/osm_overview1.jpg"><img class="size-full wp-image-58" src="http://danilogurovich.files.wordpress.com/2008/07/osm_overview1.jpg" alt="Main stakeholder activities in the Overlapping Schedule Model." width="427" height="471" /></a><p class="wp-caption-text">Main stakeholder activities in the Overlapping Schedule Model.</p></div>
<h3>The Details of the Process</h3>
<p>Collaboration exists at various points between all stakeholder groups to allow for seamless transitions and predictable behaviors.  Issues planned for release will be vetted between Business and Engineering for resourcing purposes, Developers will interface with Business to demonstrate functionality, and Engineers, Business and QA will collaborate with Release Management in the “Go-No-Go” process gate as final release is set (other collaborations are spelled out in the details below).</p>
<p>An Issue planned in one week will be released on the second Thursday following.  Metrics can be attached to every step in the process.  Everyone knows what to do and when to do it, and communication between the disparate groups are formalized and clarified.  The entire process becomes engrained within the fabric of the company.  The team implementing it becomes responsible for the continuous and uninterrupted revenue operations of the application.  This “Profit Team” process is outlined:</p>
<p> </p>
<div id="attachment_59" class="wp-caption aligncenter" style="width: 429px"><a href="http://danilogurovich.files.wordpress.com/2008/07/osm_single_cycle.jpg"><img class="size-full wp-image-59" src="http://danilogurovich.files.wordpress.com/2008/07/osm_single_cycle.jpg" alt="Single Cycle Process Flow for Overlapping Schedule Model" width="419" height="435" /></a><p class="wp-caption-text">Single Cycle Process Flow for Overlapping Schedule Model</p></div>
<h2>The Steps</h2>
<h2>Starting at the End – Release</h2>
<p><em>Time: Thursday, 2pm</em></p>
<p>Release is scheduled for Thursday at 2pm. This is no arbitrary time. Releases should never occur on Fridays or Mondays because there is no time for <em>Go-No-Go</em> meetings or mitigation in the event of emergencies. Tuesdays and Wednesdays are also out because of the need to QA all issues thoroughly, and this has to happen through unbroken week and not broken up by a weekend. (Mon-Fri).</p>
<p>Thursday becomes the release day by elimination.  It is impossible to release first thing in the morning (the <em>Go-No-Go</em> meeting must occur first), and time must be made for a “burn in” period after release to production. This means that after lunch is the best time, but since preparation must occur immediately before the release, so it can&#8217;t be done before lunch  (e.g.Thursday, 2pm).”</p>
<p>The Release of the current, tested and accepted code signifies the very end of the process and the beginning of a new one, so this point is a perfect place to point out the criteria for starting the next cycle &#8212; this occurs when new enhancements have been identified and a decision has been made to move them forward into production.</p>
<p>These identified issues are only in their basic state. They have no prioritization. All of their requirements may not be complete, and the majority certainly haven’t been resourced.  They are probably known only to the business stakeholders and have no release date.</p>
<h3>Adding New Enhancements/Maintenance to the Issue Tracker</h3>
<p><em>Time: Thursday Morning – Friday Morning</em></p>
<p>Identified Issues are entered into the Issue Tracking System with their status marked as <em>“Prioritization”</em>. Once all the issues are added to the Tracking system, the process can move forward. At this point, the business stakeholders are still the only group <em>actively</em> involved in the process.</p>
<h3>Add Supporting Docs</h3>
<p><em>Time: Thursday Morning – Friday Morning</em><br />
With all the issues in the Tracking System, any supporting documentation that is available at this point is added to the corresponding issue, along with any commentary that will give the prioritization committee enough information to put the issues in the right order for development and eventual release.</p>
<h3>Prioritization – The First Big Step</h3>
<p><em>Time: Friday Noon</em><br />
Lunch is served as Business Stakeholders engage to prioritize the issues in the system for eventual deployment.  Still only a Business Stakeholder exercise, the process is now setting up to collaborate with the rest of the stakeholders.  Issues are prioritized and prepared to meet the Development Managers for mapping to resources.</p>
<h3>Meet the Engineers – Dev/Resource Alignment Meeting</h3>
<p><em>Time: Friday Afternoon</em><br />
The Program Coordinator for the business generates a report containing all issues prioritized for the next release. Their status at this time should be marked as <em>“Requirements”</em> in the Issue Tracker. The Coordinator and Development Manager(s) should be prepared meet and map each issue to Engineering Resources for Implementation. The Program Coordinator will go through each issue with the Manager(s), and the Managers will assign a resource to each issue. At this point a “contract” is being made between the Business and Development groups, spelling out just what can and will be done for the next release cycle.</p>
<p>It is the Development Manager’s responsibility to carefully look at each Issue and ensure that most, if not all requirements are complete and formatted for maximum understanding with respect to the assigned engineer. All gaps must be pointed out and recorded against each issue for its corresponding business owner’s follow-up.</p>
<p>It is also possible that the prioritized issues may lack the development resources necessary to for completion within the next release cycle (developers may be unavailable, an emergency may have supplanted resources, etc.). When this occurs, they will be re-prioritized and sent back into the queue for the next week. A team can only do so much, and creating situations requiring extraordinary effort will “raise the bar” and eventually burn out the team. Consistency is critical, and this step is the decision gate to ensure that all follow-on processes go smoothly.</p>
<p>Once all issues have been mapped to resources and the Business-to-Development hand-off is complete, all issues that are to be worked on are marked <em>“Ready for Development”</em>.</p>
<h3>Finalize Requirements</h3>
<p><em>Time: Friday Afternoon – Monday Morning</em><br />
At this point, there is an “Engineering Perspective” to the issues. The Program Coordinator has the opportunity to work with the stakeholders of the individual issues and update any requirements and answer any questions that have arisen from the Dev/Resource Alignment meeting. The stakeholders can have some informal contact with their assigned engineer, and set up stakeholder – engineer/developer meeting, also known as a JAD session.</p>
<h3>Dev/Biz JAD session – Is This What You Want?</h3>
<p><em>Time: Monday 11am</em></p>
<p>As soon as possible on the Monday morning of the Development week, the Business Stakeholder and any other interested parties should meet with the assigned developer of the Issue to have an overview of what is to be built and positively identify every unclear detail surrounding it’s development. This is called a Joint Application Design/Developemnt (<strong>JAD</strong>) session.</p>
<p>The JAD process does for computer systems development what <a href="http://en.wikipedia.org/wiki/Henry_Ford"><span>Henry Ford</span></a> did for the manufacture of automobiles (a method of organizing machinery, materials, and labor so that a car could be put together much faster and cheaper than ever before – the assembly line). The goal in systems development is to identify what the users really need and then set up a system or process that will provide it. Traditional methods have several built-in delay factors that get worse as more people become involved. JAD cures this by addressing four simple assumptions:</p>
<ul>
<li>People who actually do a job have the best understanding of that job.</li>
<li>People who are trained in information technology have the best understanding of the possibilities of that technology.</li>
<li>Information systems and business processes rarely exist in isolation &#8212; they transcend the confines of any single system or office and affect work in related departments. People working in these related areas have valuable insight on the role of a system within a larger community.</li>
<li>The best information systems are designed when all of these groups work together on a project as equal partners.</li>
</ul>
<p>The outcome of the JAD session should show in evidence:<br />
   </p>
<ul>
<li>Definition of the Issue to the satisfaction of both parties.</li>
<li>Understanding and translation of all requirements</li>
<li>Obtained approval from all parties with respect to the forward development of the issue.</li>
<li>Surety that all decisions and changes are reflected in the Issue Tracker.</li>
<li>An Agreed upon time for demonstration before the code is checked in for QA</li>
</ul>
<p>With the completion of this step, the Issue is marked “In Development”.</p>
<p><em>For more information on a JAD session, consult </em><a href="http://www.umsl.edu/~sauterv/analysis/JAD.html">http://www.umsl.edu/~sauterv/analysis/JAD.html.</a><a href="http://www.umsl.edu/~sauterv/analysis/JAD.html"></a></p>
<h3>Development – Where the Rubber Meets the Road</h3>
<p><em>Time: Monday 11am – Friday 12pm</em></p>
<p>The Developer will now build what has been set forth in the Issue Tracker and based upon the learnings from the JAD session. If any problems or roadblocks occur, they should log the problem clearly in the Issue Tracker, mark the Issue “Development Problem”, and notify their Manager and the Stakeholder for the Issue.</p>
<p>Development on the issue can continue until the Code Freeze/Check-in time of Friday, 12pm. Any Issues being worked on after that point are at risk for being pushed off to another cycle, and will need to be addressed by stakeholders.</p>
<p>As necessary, a demonstration should take place based upon a time set up in the JAD session. This demonstration should answer the question “is this what you asked me to build?”  It is important to have some time left in the Development Week to make any last minute corrections to the implementation.</p>
<p>During the Development Cycle, the QA team will be pulling the Issues that are to be tested from the Reporting System of the Issue Tracker, and setting up their tests. They may be asking any Stakeholders questions based upon the testing needs of the particular issue.</p>
<h3>Ready For QA Code Check-in</h3>
<p><em>Time: Friday 12pm</em></p>
<p><em></em>All code is checked into the Source Control System at the Friday deadline. The Release manager will merge the newly developed code into QA Branch. The QA team will begin reviewing issues to set up tests and begin next week’s three-day testing cycle.</p>
<p>Developers will prepare next for the next Development Week. All checked in Issues status is set &lt;em&gt;“Ready for QA”&lt;/em&gt; at time of check in.</p>
<blockquote><p><em>It is important to check development code in when finished and not wait till the last minute to prevent collisions, over-writing of code and any last minute problems that can surround more than one person trying to check in the same file(s). Check in soon and often should be a mantra.</em></p></blockquote>
<h3>Sandbox Demo to Business</h3>
<p><em>Time: Friday Afternoon</em></p>
<p><em></em>Developers demonstrate changes to Business Stakeholders on an “as needed basis” . All Business Stakeholders sign off on their particular issues and agree that QA can take over and start testing. This is the Final gate check for Development. Issue Tracker Status is marked &lt;em&gt;“QA”&lt;/em&gt; by QA personnel.</p>
<p> </p>
<div id="attachment_65" class="wp-caption alignleft" style="width: 138px"><a href="http://danilogurovich.files.wordpress.com/2008/07/qa-processes2.jpg"><img class="size-thumbnail wp-image-65" src="http://danilogurovich.files.wordpress.com/2008/07/qa-processes2.jpg?w=128" alt="Dev/QA process &quot;swim lanes&quot; - blended colors represent collaborations. click to enlarge." width="128" height="88" /></a><p class="wp-caption-text">Dev/QA process &quot;swim lanes&quot; - blended colors represent collaborations. click to enlarge.</p></div>
<h3>QA Complete, Final Business Check</h3>
<p><em>Time: Wednesday afternoon</em><br />
The business stakeholder will view the corresponding implementations to their issues served from the QA machines. Any final defects may be addressed, or the Issue may be delayed for another cycle.<br />
If all is ok, the Issue Tracker Status for QA complete is <em>“Ready for Production”</em>.  Business has final say. </p>
<h3>Move Code to Head/Staging</h3>
<p><em>Time: Wednesday 4pm</em><br />
Release manager will take all issues marked <em>“Ready for Production”</em> and merge to the Production Staging Branch.  If Staging exists, it is set to staging for final demonstrations, review and any business collaborations on an as-needed basis  (sometimes there are outside dependencies that may need to have a “production-level” deployment to expose any final issues, or be observed by external stakeholders.  This is the place to do this.</p>
<h3>Last Minute Gut Check</h3>
<p><em>Time: Thursday Morning</em><br />
Final Business reviews.  Go-No-Go meeting.  Any last minute issues are addressed before launch.  Afternoon begins with ITOPS/Release Coordination for Production and launch.</p>
<h3>Release – OK, Let’s start at the top!</h3>
<p><em>Time: Thursday, 2pm</em><br />
Code is launched to production.  The deployment must be watched throughout the afternoon for any production/emergency issues.  Business stakeholders should review their changes on production sites.  Any outside communication with external stakeholders is handled.  Issues marked <em>“Production”</em> in Issue Tracker.  Issues from previous week marked <em>“Production”</em> are now marked <em>“Closed”</em>.</p>
<h2>The Three P Method:  P1, P2, P3.</h2>
<p>Below is an industry-standard practice of prioritizing issues with respect to their urgency.  They are categorized as P1 – P3, the most urgent being P1.  Each has impact to issues that are “already” in the queue for development, which must be taken under consideration.</p>
<ul>
<li>P1 &#8212; when a fix is needed to affect a serious break that will affect the company legally, morally, or for revenue impact over a set value (usually 50k or so).  Everything is dropped and a release to production is done ASAP, outside of the schedule.  Depending upon the impact, an upcoming release may be delayed for a week or certain issues may not be completed for the next scheduled release.  A post-mortem is required to decide what the effect to the normal schedule is.<em>A P1 fix usually requires a VP for “go-forward” approval. Often a meeting of stakeholders must occur to gather information with respect to impact and fixes.</em></li>
<li>P2 &#8212; when a fix is needed to affect a break within the system.  In this scenario, the break is fixed for the very next scheduled release &#8212; other issues being worked on may be affected, but no special release is done.  Only in the rarest of cases is a Post-Mortem needed.  Needs Director-level approval.</li>
<li>P3 &#8212; anything within the normal schedule.  Planned for one week, developed for a week, QA&#8217;d and released the following week.</li>
</ul>
<h2>The Overlapping Schedule Model Process within the Issue Tracker</h2>
<p>The JIRA issue tracking system aligns workflow with Issues to allow for clean and simple end-to-end tracking of issues aligned closely to physical business processes.  It employs a “status-transition” method to follow the process.  Each “status” may have various “transitions” that allow for different scenarios.  By clicking on a particular transition, the workflow will change to a corresponding status, and the path chosen will be reflected in the next available transitions available to the JIRA User.</p>
<p>The Diagram below shows the workflow available to the Team using JIRA and implementing the Overlapping Schedule Model.  The workflow has been mapped out and attached to the Schemes available to the IHO.  This model can be used or extended for other development channels.  Note various paths that do not take a particular Issue into production, and other paths that have various conditions that must be satisfied to move forward.  The “straightest” path to production is indicated by bold blue lines, showing the transitions and their corresponding status indicators.</p>
<div id="attachment_66" class="wp-caption alignleft" style="width: 138px"><a href="http://danilogurovich.files.wordpress.com/2008/07/osm.jpg"><img class="size-thumbnail wp-image-66" src="http://danilogurovich.files.wordpress.com/2008/07/osm.jpg?w=128" alt="Overlapping Schedule Model Workflow. click to enlarge" width="128" height="95" /></a><p class="wp-caption-text">Overlapping Schedule Model Workflow. click to enlarge</p></div>
]]></content:encoded>
			<wfw:commentRss>http://gurovich.com/site/2008/07/22/the-overlapping-schedule-process-for-maintenance-and-enhancement-of-complex-web-properties/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
