<?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>progress.solvepoint.com &#187; Anti-patterns</title>
	<atom:link href="http://progress.solvepoint.com/tag/anti-patterns/feed/" rel="self" type="application/rss+xml" />
	<link>http://progress.solvepoint.com</link>
	<description>Progress Blog - OpenEdge, WebSpeed, Sonic, 4GL, ABL, QAD, Epicor, and all things Progress</description>
	<lastBuildDate>Sat, 15 May 2010 18:29:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>OpenEdge ABL Phantom Error</title>
		<link>http://progress.solvepoint.com/2007/11/30/openedge-abl-phantom-error/</link>
		<comments>http://progress.solvepoint.com/2007/11/30/openedge-abl-phantom-error/#comments</comments>
		<pubDate>Fri, 30 Nov 2007 22:58:52 +0000</pubDate>
		<dc:creator>JohnK</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Reliability]]></category>
		<category><![CDATA[Anti-patterns]]></category>
		<category><![CDATA[Phantom Errors]]></category>

		<guid isPermaLink="false">http://progress.solvepoint.com/2007/11/30/openedge-abl-phantom-error/</guid>
		<description><![CDATA[At Solvepoint we&#8217;ve coined a new term, the Phantom Error.   What is a Phantom Error you ask?  Well, it is an undesirable circumstance where the Progress VM decides to raise the error condition but leaves error-status:get-message() set to the empty string.
This , of course, can lead to a host of ugly sorts [...]]]></description>
			<content:encoded><![CDATA[<p>At Solvepoint we&#8217;ve coined a new term, the Phantom Error.   What is a Phantom Error you ask?  Well, it is an undesirable circumstance where the Progress VM decides to raise the error condition but leaves error-status:get-message() set to the empty string.</p>
<p>This , of course, can lead to a host of ugly sorts of bugs not the least of which is not having any idea where the error happened or why.</p>
<p>Here is a simple example that demonstrates a Phantom Error:</p>
<blockquote>
<pre><span style="color: #8b0000;">DEFINE NEW GLOBAL SHARED VARIABLE myHandle AS HANDLE NO-UNDO.</span><span style="color: #8b0000;">
</span><span style="color: #8b0000;">main: DO ON ERROR UNDO main, RETRY main:
  IF RETRY THEN do:
    MESSAGE RETURN-VALUE error-status:get-message(1) VIEW-AS ALERT-BOX.
    LEAVE main.
  END.</span>
<span style="color: #8b0000;">  RUN someProc IN myHandle.</span>
<span style="color: #8b0000;">END.</span></pre>
</blockquote>
<p>You&#8217;ll notice that both return-value and get-message(1) return blank.</p>
<p>If you happen to be in a terminal based procedure editor, however, you will receive the error message in the &#8220;message area&#8221; at the bottom.  Unfortunately, this doesn&#8217;t do much good for server code.</p>
<p>As a consequence, server code will typically swallow these Phantom Errors at worst, or report the error out of context at best.</p>
<p>So, what can be done? Diligent error trapping is called for.  Protect the code by always testing handles before using them.</p>
<p>Unfortunately, this isn&#8217;t the only type of code that will produce a Phantom Error.   We will discuss other Phantom Errors under the Tag &#8220;<a title="Phantom Errors" href="http://progress.solvepoint.com/tag/phantom-errors/">Phantom Errors</a>&#8221; in other posts.</p>
]]></content:encoded>
			<wfw:commentRss>http://progress.solvepoint.com/2007/11/30/openedge-abl-phantom-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenEdge Memory Management Anti-pattern</title>
		<link>http://progress.solvepoint.com/2007/11/30/openedge-anti-pattern/</link>
		<comments>http://progress.solvepoint.com/2007/11/30/openedge-anti-pattern/#comments</comments>
		<pubDate>Fri, 30 Nov 2007 17:56:31 +0000</pubDate>
		<dc:creator>JohnK</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance Tuning]]></category>
		<category><![CDATA[Reliability]]></category>
		<category><![CDATA[Anti-patterns]]></category>
		<category><![CDATA[Memory]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://progress.solvepoint.com/2007/11/30/openedge-anti-pattern/</guid>
		<description><![CDATA[Hello all,
I&#8217;ve recently been reviewing some Progress 4GL and have found an all too common anti-pattern related to memory management.
When a variable is defined, the Progress runtime client (Virtual Machine) allocates memory at runtime for that variable.   Once the variable is out of scope, the memory is released and everyone is happy.  [...]]]></description>
			<content:encoded><![CDATA[<p>Hello all,<br />
I&#8217;ve recently been reviewing some Progress 4GL and have found an all too common anti-pattern related to memory management.</p>
<p>When a variable is defined, the Progress runtime client (Virtual Machine) allocates memory at runtime for that variable.   Once the variable is out of scope, the memory is released and everyone is happy.   Progress programmers have grown comfortable with this design and obliviously define variables whenever they are needed knowing that they will be de-allocated automagically by the Progress VM.</p>
<p>Then came dynamic objects.</p>
<p>Progress programmers were overjoyed!  They could now create temp-tables, buttons, queries all on the fly at runtime.  No more convoluted if-then statements or .i&#8217;s or having to code a different &#8220;for each&#8221; for every combination of where clause.</p>
<p>However, as with any power bestowing feature, there is a dark side to this wonderful new world of dynamic 4gl:  memory management.  Most programmers never really stopped to consider the fact that if something is created dynamically at runtime, the VM has no way of knowing the <u>scope</u>.  It cannot tell <u>when</u> to release the memory required for the dynamic object.  REMEMBER:  the scope of the variable you happen to assign the object to HAS NO BEARING on the scope of the OBJECT since it can be passed around.  In other words, the scope of the variable holding the HANDLE to the object is NOT bound to the OBJECT itself.  The scope of ALL OBJECTS are always at the SESSION.  This applies to GUI widgets, dynamic queries, temp-tables, etc.</p>
<p>Java (and other VM&#8217;s) solve this through the use of a separate execution thread running concurrently called a Garbage Collector.  Its job is to scan memory and find dynamic objects that are no longer &#8220;reachable&#8221; and release their memory.  Unfortunately, the Progress VM has no such thread/concept.</p>
<p>To add insult to injury, not only does this leak memory but it also causes progressively worse performance:  The more widgets in memory, the more time it takes to create another widget.  Here are three examples (run on a 2.1ghz processor):</p>
<h3>Button Handles</h3>
<p><img src="http://progress.solvepoint.com/wp-content/uploads/2007/12/create1000buttonhandles.gif" alt="Create 1000 Button Handles" /></p>
<blockquote>
<pre>Minimum memory required/lost per Button Handle: 512 bytes</pre>
</blockquote>
<h3>Query Handles</h3>
<p><img src="http://progress.solvepoint.com/wp-content/uploads/2007/12/create1000queryhandles.gif" alt="Create 1000 Query Handles" /></p>
<blockquote>
<pre>Minimum memory required/lost per Query Handle: 1024 bytes</pre>
</blockquote>
<h3>Temp-Table Handles</h3>
<p><img src="http://progress.solvepoint.com/wp-content/uploads/2007/12/create1000temptablehandles.gif" alt="Create 1000 Temp-Table Handles" /></p>
<blockquote>
<pre>Min. memory required/lost per Temp-Table Handle: 512 bytes</pre>
</blockquote>
<p>So, as you can see, from both a memory and CPU footprint standpoints, it is very important to be sure to clean up your objects.</p>
<p>This may seem like a large number of handles, but remember two important points:<br />
1. This is at the <u>session</u> level.  This means that if a.p calls b.p which creates objects then those will exist for the life of the session: THERE IS NO SCOPE other than SESSION FOR DYNAMIC OBJECTS and they are NEVER automatically reclaimed!<br />
2. If the programs are running as part of a long-running session such as AppServer, EagleIQ server or Webspeed, then you have to consider the cumulative affect over days, weeks or months.<br />
Also note that if it is a temp-table, it could potentially have a much larger memory footprint.</p>
<p>So, what must be done?<br />
It is up to the Progress programmer to clean up each and every dynamic object created using the &#8220;delete object&#8221; command.<br />
It may be appropriate to create a widget-pool in which to assign your objects so you can just delete the pool and all the objects within will be released as well.  In fact, if you create a non-persistent widget-pool, it will be automatically deleted when it goes out of scope.  Creating the object into a non-persistent pool will make it behave as if it were scoped at the level that the widget-pool is created:  in effect, making it behave as if it were statically defined.</p>
<p>If you don&#8217;t use a non-persistent widget-pool, then It is also important to be sure the &#8220;clean up&#8221; code is executed even when there is an error.  For example, the following will bleed memory if an error condition is raised within the blah blah:</p>
<pre><font color="#8b0000">      procedure doQuery:
          def var qh as handle.
          create query qh.
          /* so some business logic here */
          do while true:
               blah blah
          end.
          delete object qh.
     end.</font></pre>
<p>However,  if you create a non-persistent widget pool, then it is automatically deleted when it goes out of scope.  So the following will not leak memory even if an error condition happens:</p>
<blockquote>
<pre><font color="#8b0000">procedure doQuery:</font>
<font color="#8b0000">    def var qh as handle.</font>
<font color="#8b0000">    create widget-pool "wp".</font>
<font color="#8b0000">    create query qh in widget-pool "wp".</font>
<font color="#8b0000">    /* so some business logic here */</font>
<font color="#8b0000">    do while true:</font>
<font color="#8b0000">         blah blah</font>
<font color="#8b0000">    end.</font>
<font color="#8b0000">    delete object qh.</font>
<font color="#8b0000">end.</font></pre>
</blockquote>
<p>The widget-pool may be defined at the .p level as well.  In this case the pool is deleted when the .p is exited.</p>
<p>Oh, by the way, persistent procedures and memptr&#8217;s  are two other constructs that have a session level scope.  However, they <u>cannot</u> be part of a widget-pool and therefore must be handled individually.</p>
]]></content:encoded>
			<wfw:commentRss>http://progress.solvepoint.com/2007/11/30/openedge-anti-pattern/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

