tag:blogger.com,1999:blog-24784830502228363962024-03-14T03:49:56.754-07:00Rowe Boat ProgrammerAnonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.comBlogger11125tag:blogger.com,1999:blog-2478483050222836396.post-91977597274842140072017-07-25T10:36:00.001-07:002017-07-25T10:44:31.371-07:00SharePoint Workflows: Going Against the Flow #1<p>My latest project has me working with SharePoint workflows. In this case, I have some JavaScript that I wrote that uses <a href="https://mozilla.github.io/pdf.js/">PDF.js</a> to see if a PDF document has been signed, how many signatures are present, and which names are associated with those signatures. (My thanks to <a href="https://pkijs.org/examples/PDFexample.html">PKJIS</a> for a working example that gave me a good launching point.) The JavaScript uses the SharePoint API to retrieve the list of people that are supposed to sign the document and the list of people that are supposed to be notified when a signature is affixed to the document before storing this information as metadata for the document.</p>
<p>These modifications to the metadata then fire off a SharePoint workflow. If you've worked with SharePoint workflows, you know that they have some serious shortcomings, especially if you can't use Visual Studio to build workflow functionality in C#.</p>
<p>The JavaScript stores the names of the people who signed the document in a "Multiple Lines of Text" field; each name is on its own line. The metadata for the document includes a field called "Last Count" that is only updated by the SharePoint workflow. When the document is changed, the SharePoint workflow counts the number of lines in the Signatures field and compares that count with "Last Count". If the two values are different, an email is sent out to the person who should sign the document next and the people that are monitoring the signatures.</p>
<p>Here is what the workhorse portion of the workflow looks like:</p>
<ol type="I">
<li>Set <u>Variable: CountSignatures</u> to <u>0</u>.</li>
<li>then Set <u>Variable: CountCompleted</u> to <u>No</u>.</li>
<li>then Set <u>Variable: IndexNextSignature</u> to <u>0</u>.</li>
<li>
<strong>Loop: through Signatures</strong><br />
The contents of this loop will run repeatedly while <u>Variable: CountCompleted</u> <u>equals</u> <u>No</u>
<ol type="A">
<li>
Copy from <u>Current Item:Signatures</u>, starting at <u>Variable: IndexNextSignature</u> (Output to
<u>Variable: TempSignatures</u>)
</li>
<li>If <u>Variable: TempSignatures</u> <u>is not empty</u>
<ol type="1">
<li>
Replace <u title="Open the string builder and hit the <Enter> key once for a new line character">\n</u> in
<u>Variable: TempSignatures</u> (Output to <u>Variable: TempSignatures</u>)</li>
<li>Find <u><br></u> in <u>Variable: TempSignatures</u> (Output to <u>Variable: FindTag</u>)</li>
<li>
then Calculate <u>Variable: CountSignatures</u> <u>plus</u> <u>1</u> (Output to <u>Variable:
CountIncremented</u>)
</li>
<li>then Set <u>Variable: CountSignatures</u> to <u>Variable: CountIncremented</u></li>
<li>
If <u>Variable: FindTag</u> <u>is greater than or equal to</u> <u>0</u>
<ol type="a">
<li>Set <u>Variable: LengthNextSignature</u> to <u>Variable: FindTag</u></li>
<li>
then Calculate <u>Variable: LengthNextSignature</u> <u>plus</u> <u>4</u> (Output to <u>Variable:
LengthIncremented</u>)
</li>
</ol>
Else
<ol type="a">
<li>Set <u>Variable: CountCompleted</u> to <u>Yes</u></li>
</ol>
</li>
</ol>
Else
<ol type="1">
<li>Set <u>Variable: CountCompleted</u> to <u>Yes</u></li>
</ol>
</li>
<li>
If <u>Variable: CountCompleted</u> <u>equals</u> <u>No</u>
<ol type="1">
<li>
Calculate <u>Variable: IndexNextSignature</u> <u>plus</u> <u>Variable: LengthIncremented</u> (Output to <u>Variable: IndexIncremented</u>)
</li>
<li>
then Set <u>Variable: IndexNextSignature</u> to <u>Variable: IndexIncremented</u>
</li>
</ol>
</li>
</ol>
</li>
</ol>
<p>I can do all of this in one line of JavaScript code:</p>
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi8-SR1smakNO6ESQqIlVk27T96d2tluY_EVtYXvBqt5LvRG2Y5NF-5cl6-DQE8Fiappqc518qLjHszm0VSh7NDZLHls_3K36j1BX3oL0g_lMRqqpTh8HrwtCq0qHI-J7Y5F6iC_IOCbJJ/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;">var countSignatures = signatures.replace(/\n+/g, "<br>").split("<br>").length;</code></pre>
<p>What's more, I don't have to worry about whether the <tt>signatures</tt> variable is empty or not. SharePoint throws an exception if you try to use the "Find Substring in String" action and either string is empty. If Substring is empty, you get a "Divide-by-Zero" error message; if String is empty, you get a "Value cannot be null" message.</p>Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-50109085702293486982016-11-17T09:22:00.000-08:002016-11-17T09:22:38.213-08:00Mobile App Development<h2>What's been happening?</h2>
<p>For the last couple of months, I have continued looking for work. Meanwhile, I have been expanding my skill set and adding my new skills to my resume. I've also taken on a few contracts as a freelance web developer. I just released my first project for <a href="http://www.blisscarpetcleaning.com">Bliss Carpet Cleaning</a>. This project uses PHP, a language I'd only dabbled in before. I've got another PHP project in the pipelines as well as a couple of projects built on Joomla.</p>
<h2>What's next?</h2>
<p>I've been playing in my mind with an idea for a mobile app and my wife suggested another one a few days ago. I haven't done mobile app development before, but I've been intrigued by it for quite a while. I've got Cordova and Android Studio set up on my computer and I'm going to figure out what it takes to make a mobile app run. There's going to be a lot of reading in my immediate future and I hope to share some of what I learn here.</p>
<h3>Why Cordova?</h3>
<p>I chose to go with Cordova because I felt that it would be the best way for me to get a mobile solution out. As an accomplished web developer, this incorporates an existing toolset. However, I don't want a pure web app because all of my ideas rely on native functionality of the mobile device and I would need a native app or a hybrid app to access that functionality.</p>
Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-61739847424462423642016-08-17T09:03:00.000-07:002016-08-17T09:03:07.525-07:00Adventures in Three.js - Part 1<h1>Introduction</h1>
<p>Ever since I completed my undergraduate degree, I've done very little development at home. I've never had a lot of motivation to do personal projects, even though I understand some of the benefits associated with that. While personal growth is possible in a work environment, it is often stunted by deadlines, conventions, and accepted technologies. Nowhere is this more limiting than a government environment.</p>
<p>As a result, much of my personal growth has stemmed from the creation and refinement of pattern libraries. At each job, I would introduce patterns that would automate or simplify various tasks. Developing such patterns encourages growth because you aren't writing code to meet a specific need once, you're writing code to meet a specific need in several places. It requires forethought, asking questions like: "When will this be used?" "How might someone need to change the visual appearance?" "Is there a faster way to do this without sacrificing flexibility?" "Does the flexibility unduly increase the complexity?"</p>
<p>Some of the patterns I've revisited have included:</p>
<dl>
<dt>Automated tabular data display</dt>
<dd>ColdFusion provides the <tt><cfgrid></tt> tag to quickly dump the contents of a dataset. Unfortunately, it's a very old tag that has received few updates; it doesn't meet accessibility guidelines and doesn't allow much customization. I've often felt the need to automate this, so it is a pattern I've visited several times. The latest iteration made it easy to start with a basic dump and tweak the code until you got what you wanted. It automated pagination, creation of sort links, grouping of data, and calculating and displaying subtotals.</dd>
<dt>Form validation</dt>
<dd>This is a pattern I visited in Delphi and in ColdFusion, addressing many of the same requirements. The latest iteration of this made it easy to: ensure that required fields were not empty; ensure that values matched an accepted pattern; ensure that numeric values fell within a certain range; and ensure that values that should be unique were unique.</dd>
<dt>Database interaction</dt>
<dd>This was a pattern I attempted before exposure to CFWheels. The Model implementation by CFWheels is certainly a lot more robust, but I've had a certain amount of luck creating this pattern for myself. My own experience attempting this sort of automation has certainly taught me a lot. My latest iteration of this automatically retrieved the metadata for each field in a specified table and used that metadata to validate any data provided to those fields. It prevented the user from assigning values to calculated fields and automatically retrieved the values for calculated fields and auto-increment fields when a record was inserted or updated. It greatly simplified some of the work I was doing maintaining existing code to manipulate tables with more than 200 fields. Did it add overhead? Yes. Did it reduce development time? Significantly! Did it increase readability? Most assuredly it did.</dd>
</dl>
<p>I subscribe to a couple of newsletters that help me keep up with the web development community. You might understand how exciting it is to see how things are progressing. You might also understand how frustrating it can be if you can't use the technology or play with it much. I often couldn't utilize these technologies because they had usability issues, compatibility problems, or accessibility deficiencies. Nonetheless, I won't be able to keep up if I take the chance to play with the new technology.</p>
<h1>What to do?</h1>
<p>Developers tend to face some of the same problems that other creators face—writer's block—especially when starting something completely new. The more effort it takes to create a simple application that says, "Hello, world!" the harder it can be to get started. I need a project that motivates me and I need a goal. What challenge will keep me moving forward? Is there a community I can serve?</p>
<p>Of course, for me to get started, I need a simple goal to start with and, for me to keep going, I need to have long-term goals to strive for. My initial goal must be significant enough to overcome the initial writer's block and the long-term goals motivating enough to bring me back to the drawing board.</p>
<h1>Dungeon Generator</h1>
<p>I was talking with a friend about a project he was working on. He has played Dungeons & Dragons for decades and was working on a dungeon generator to learn PHP and become more familiar with AJAX. His generator works a lot like a text adventure: each room is described, but there is no overall map of the dungeon. I had toyed with this idea for a long time, having played text adventures as a kid and drawing out dungeons for my siblings to crawl, so I wanted to try a different take. Many of the dungeon generators I saw online were two-dimensional, either creating a pure two-dimensional maze and building out rooms with it or generating rooms and opening up passages between them. The deficiency, obviously, was the third dimension.</p>
<p>"This is the perfect opportunity for me to play with a JavaScript 3D library." I'd played with Phaser some in the past, but it doesn't do much in three dimensions. I decided to try out Three.js to see if I could get it to work. Within a week, I had a simple page that would ask for the dimensions of the dungeon, generate a pure three-dimensional maze, display that maze with Three.js, and allow you to fly around the outside of it. You can find the code on <a href="https://www.github.com/pfrowe/dungeon-generator/">Github</a>.</p>
<p>As I'm writing this, the current iteration of this code is creating 5x5x5 cubes and connecting them with corridors. The next thing I want to do is clean up the code. I want to create a Space class that encapsulates some of the code specific to a 5x5x5 space, such as displaying the space, checking for existing connections to the space, and checking to see if any nearby spaces are not connected. After I do that, I want to start building rooms out of these spaces. The easy path would dictate creating rectangular prisms, but an underground dungeon built out of a natural cavern wouldn't reflect this building technique, so I've come up with another algorithm that might simulate that better.</p>
<p>My aim is not only to come up with a working dungeon generator (there's a lot more to it than generating rooms and passages), but also to talk about the process. What challenges have I met? How did I overcome them or work around them? (In Dungeons & Dragons, finding a way around the challenge can also count as defeating it.)</p>Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-55036176783711854702016-02-26T14:00:00.001-08:002016-02-26T14:00:06.189-08:00ColdFusion Val function limitations<p>I was recently working with some really small numbers in ColdFusion and found that one of my typical shortcuts was actually causing me problems. Since I would retrieve information from the database and the database would return an empty string when the value was <tt>NULL</tt>, I would use ColdFusion's <tt>Val</tt> function to quickly make sure that any blank strings would become zeroes before I did arithmetic with them.</p>
<p>As mentioned above, the problem arose when I started working with really small numbers. As I'm sure most ColdFusion developers know, the language is loosely typed. If you want to display the value of a variable, ColdFusion transparently casts the variable as a string. If you want to perform arithmetic on a variable, ColdFusion transparently casts the variable as a number. If you want to perform date manipulation on a variable, ColdFusion transparently casts the variable as a date.</p>
<p>What I found regarding the <tt>Val</tt> function was that, when I was working with numbers small enough that they would be displayed in "exponent format" (a significand, followed by <tt>E</tt>, followed by the exponent), <tt>Val</tt> would only return the significand. <tt>Val</tt> was taking the string representation of the number and stopping at "<tt>E</tt>" because that is a non-numeric character. This isn't terribly unexpected, but has reduced the usefulness of the function for me.</p>Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-56347795710525662112015-12-16T12:36:00.001-08:002015-12-16T12:36:55.162-08:00Undocumented Google Calendar URL Parameter #2<p>While looking up information about the <code>sprop</code> parameter for Google Calendars, I found a <a href="http://type-writer.jp/googlecalendar_eventbuttonsgenerator/">Japanese page</a> with information about adding events to Google Calendar that included the <code>add</code> parameter. The <code>add</code> parameter allows you to define additional attendees. I've tried this with email addresses. You can specify multiple email addresses by separating them with commas. Here is an example:
<blockquote><code>add=guest@gmail.com,visitor@gmail.com</code></blockquote></p>
<p>I'm still looking for a parameter that allows you to specify notification times.</p>Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-68262540705848293892015-12-16T10:52:00.001-08:002015-12-16T12:37:02.554-08:00Undocumented Google Calendar URL Parameter #1<p>While doing some looking into ColdFusion components and research into RFC 5545, Google Calendars, and Yahoo! Calendars, I did some experimenting to see how much I can specify for a calendar event via URL in Google Calendars. I quickly found the <code>action</code>, <code>text</code>, <code>desc</code>, <code>dates</code>, and <code>location</code> parameters. Some additional looking found the <code>sprop</code> and <code>trp</code> parameters.</p>
<p>I opened up a new calendar event and tried to find ways to specify other portions of the form through URL parameters. I eventually found that I could use the <code>recur</code> parameter and specify a full <code>RDATE</code> or <code>RRULE</code> property and value string in URL-encoded format. For instance, if you wanted to create an event that repeated monthly on the second Sunday, you could add:
<blockquote><code>recur=RRULE%3AFREQ%3DMONTHLY%3BWKST=SU%3BBYDAY%3D2SU</code></blockquote>
to the URL. That's a URL-encoded form of the following.
<blockquote><code>RRULE:FREQ=MONTHLY;WKST=SU;BYDAY=2SU</code></blockquote>
</p>
<p>I didn't find this documentation anywhere else, so I'm posting it here for someone else to find.</p>
<p>I'm still looking for ways to specify reminders and attendees. If you know how to do either of these, let me know.</p>Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-84322330486020740132015-02-03T14:24:00.000-08:002017-07-25T10:25:05.900-07:00Discoveries in Familiar Languages #1<p>I love it when I'm working in a familiar programming language and find something new, particularly if that something new gives me more power or simplifies a pattern I've been using for a while. Such a discovery happened today.</p>
<h1>Many-to-many relationship maintenance</h1>
<p>I am constantly setting up and maintaining many-to-many relationships. I often set up the junction table to prevent duplication of relationships by adding a unique index on the appropriate key columns. Here's an example of such a junction table in MS SQL Server.</p>
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi8-SR1smakNO6ESQqIlVk27T96d2tluY_EVtYXvBqt5LvRG2Y5NF-5cl6-DQE8Fiappqc518qLjHszm0VSh7NDZLHls_3K36j1BX3oL0g_lMRqqpTh8HrwtCq0qHI-J7Y5F6iC_IOCbJJ/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> CREATE TABLE [dbo].[ContactsGroups](
[keyContactGroup] [int] IDENTITY(1,1) NOT NULL,
[keyContact] [int] NOT NULL,
[keyGroup] [int] NOT NULL,
CONSTRAINT [PK_ContactsGroups] PRIMARY KEY CLUSTERED ([keyContactGroup] ASC) ON [PRIMARY]
)
</code></pre>
<p>This is a pretty typical, very simple junction table. When I need to maintain this many-to-many relationship, I've typically taken a two-step process: DELETE and INSERT. Here is an example of those two queries as they would appear in ColdFusion.
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi8-SR1smakNO6ESQqIlVk27T96d2tluY_EVtYXvBqt5LvRG2Y5NF-5cl6-DQE8Fiappqc518qLjHszm0VSh7NDZLHls_3K36j1BX3oL0g_lMRqqpTh8HrwtCq0qHI-J7Y5F6iC_IOCbJJ/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> <cfquery datasource="..." result="qry_updateContact_groups">
DELETE FROM [ContactsGroups]
WHERE ([keyContact] = <cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keyContact#" />)
<cfif ListLen(Form.keysGroups) GT 0>
AND ([keyGroup] NOT IN (<cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keysGroups#" list="true" />))
</cfif>
</cfquery>
<cfif ListLen(Form.keysGroups) GT 0>
<cftry>
<cfquery datasource="..." result="qry_updateContact_groups">
INSERT INTO [ContactsGroups] ([keyContact], [keyGroup])
SELECT <cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keyContact#" />, [Groups].[keyGroup]
FROM [Groups]
LEFT JOIN (
SELECT [keyGroup]
FROM [ContactsGroups]
WHERE ([keyContact] = <cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keyContact#" />)
) [ContactsGroups]
ON ([ContactsGroups].[keyGroup] = [Groups].[keyGroup])
WHERE (
[Groups].[keyGroup] IN (
<cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keysGroups#" list="true" />
)
) AND (COALESCE([ContactsGroups].[keyGroup], 0) = 0)
</cfquery>
<cfcatch><!--- An exception is thrown when nothing is inserted. ---></cfcatch>
</cftry>
</cfif>
</code></pre>
<p>As you can see, this involved performing a LEFT JOIN to exclude items that already exist in the table. Today, while looking up a related issue (see the comments in the <cfcatch> block), I found a much easier way to write the same INSERT query.</p>
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi8-SR1smakNO6ESQqIlVk27T96d2tluY_EVtYXvBqt5LvRG2Y5NF-5cl6-DQE8Fiappqc518qLjHszm0VSh7NDZLHls_3K36j1BX3oL0g_lMRqqpTh8HrwtCq0qHI-J7Y5F6iC_IOCbJJ/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> <cftry>
<cfquery datasource="#Request.ds.site#" result="qry_updateContact_groups">
INSERT INTO [ContactsGroups] ([keyContact], [keyGroup])
SELECT <cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keyContact#" />, [keyGroup]
FROM [Groups]
WHERE ([keyGroup] IN (<cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keysGroups#" list="true" />))
EXCEPT
SELECT [keyContact], [keyGroup]
FROM [ContactsGroups]
WHERE ([keyContact] = <cfqueryparam cfsqltype="cf_sql_integer" value="#Form.keyContact#" />)
</cfquery>
<cfcatch><!--- An exception is thrown when nothing is inserted. ---></cfcatch>
</cftry>
</code></pre>
<p>Note the use of the EXCEPT keyword. This operates very similarly to the UNION keyword, but performs practically the opposite operation. Instead of creating a result set with the results of the first query followed by the results of the second query, it creates a result set with the results of the first query excluding results matching those of the second query. It performs the same task I was doing before, but it's more concise and (bonus!) more readable.</p>
Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-48989764458083312052014-05-25T21:22:00.000-07:002014-05-25T21:22:30.662-07:00Confessions of a Type 2 Developer<p>I recently read an article that divided workers into two types and illustrated the second type with a story about a child building a sand castle. I can't remember if this was a blog post or a Facebook post. I'll try to outline the gist of what I remember about the two types of workers.</p>
<h3>Two Types of Workers</h3>
<p>We visit a small, undeveloped village built about a mile away from a small river. Every day, the men of the village go down to the river and retrieve water, filling cisterns with what they bring back. These cisterns are used to draw water for the people to drink or water their crops. Most of the men (we will call them Type 1 Workers) carry back enough water to fill one cistern each. However, there is one man (we call him a Type 2 Worker) who only brings back for his family to drink and they have to rely on water others retrieve to water their crops.</p>
<p>The Type 1 Workers scoff at the Type 2 Worker because his contribution is so much smaller. However, one day, we see that the Type 2 Worker has completed a project that completely upsets the balance. He's built a wooden channel that diverts water from the river directly to the village. There is no more need for people to walk a mile to the river and back to get water.</p>
<p>The tables have turned now. The Type 1 Workers feel short-changed because they have been performing so much more work for so long, but now the Type 2 Worker is getting the attention because of his project. The Type 1 Workers have been working a lot longer and a lot harder, but the Type 2 Worker has invalidated the need to do that anymore and is getting more attention for his time-saving project.</p>
<p>The illustration that accompanied this story was about a child who had built a sand castle some ways up from the high tide mark. However, he wanted to have a moat and realized that, whenever he brought water up from the sea, the water was quickly absorbed by the sand. In an effort to keep water in his moat, he started digging a channel from the level of the sea to his castle. It wasn't long before more people joined in and helped him build his channel to keep water in the moat around his castle.</p>
<h3>Two Types of Developers</h3>
<p>As in the story above, there are also two types of developers. Most developers are Type 1 Developers who, familiar with an existing set of tools and overwhelmed by deadlines, stick with the techniques they know and write their code using those techniques. A few developers are Type 2 Developers who, frustrated with copying, pasting, and tweaking code over and over again, search for ways to simplify the process. These Type 2 Developers are meeting some of the same deadlines, but they are willing to risk missing the deadline in order to divert a little time here and there to build automation and write templates that they see as time-savers in the future. "If I can get this right, this process will be a lot easier."</p>
<p>I am a Type 2 Developer. I love to build tools. I was building tools from the time I was asked to build a menu-driven console application with no functions longer than ten lines (including whitespace). Where most of my classmates built switch-case statements that ran hundreds of columns wide in order to fit within the line count limitation, I built a template object that allowed me to simply write <tt>menuObject.AddCommand(funcToRun, keyTrigger)</tt> and the object handled the rest once I wrote <tt>menuObject.GetCommand()</tt>. One of my first development jobs was in a shop that used C/C++. When I was confronted with functions over 3,000 lines long, I started finding ways to reduce the line count. Since then, I have consistently looked for opportunities to build tools that reduce development time.</p>
<p>The trade-off is that I sometimes spend so much time working on the time-saving device that I start running into problems with my deadlines. Of course, one such as myself is never quite happy with the time-saving device. "I wonder if I can get it to do <em>this</em>." "I wish it could do <em>that</em> faster." "Let me see if I can use <em>this technique</em> I just read about."</p>
<p>There is a great sense of joy when you develop a time-saving device and other developers discover it and like what you've done. If you find yourself writing the same code over and over again and tweaking it only slightly, try finding a way to automate it and experience the euphoria that results when you use your automation time and time again.</p>Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-70390747174503839132014-03-26T17:30:00.001-07:002014-03-26T20:33:37.691-07:00Good Coding Practices and the Real WorldI was reading a blog post by Adam Cameron, <a href="http://cfmlblog.adamcameron.me/2014/03/an-insight-into-mind-of-cfml-developer.html">An Insight Into the Mind of a CFML Developer</a>, and, like Adam, had some similar thoughts to what Adam and others from the development community said. The essential gist of the comment that started this was, "ColdFusion used to be such a simple language; why did you (the developers) have to make it so complicated that an amateur can't master it anymore?"<br />
<br />
<blockquote>
It was attractive because it was easy and easy to make a database enabled application.</blockquote>
ColdFusion is still an easy language to learn; that has not changed. It is easier to make a database-enabled application in ColdFusion than it is in any other server-side scripting language. I've made database-enabled applications in ASP and PHP, too; ColdFusion makes it easier to develop database-enabled applications than either of those.<br />
<br />
<blockquote>
I think the community has ruined CF.</blockquote>
Everyone is entitled to their opinion. I think that ColdFusion has improved a lot from where it was. I've worked with CF5, CFMX7, ACF9, and ACF10. With a college education primarily using C++ and field experience in C/C++ and Delphi, I watched ColdFusion as it grew. Saying that CF has been ruined is like telling someone they're ugly because they don't look like a baby anymore. ColdFusion is no longer a child. It's more of a teenager: a bit gangly, still growing into adulthood as it attempts to mimic some of the more mature languages.<br />
<br />
<blockquote>
Ya all want to code in java script make everything OO, put everything in a cfc.</blockquote>
I love the black-box effect that object-oriented programming affords. Apparently, this poster does, too, but doesn't realize it. On the one hand, the poster says that he likes how easy it is to make a database-enabled application, yet doesn't like object-oriented programming. Object-oriented programming is at the core of modern, reusable code; it allows you the developer to simplify the tasks you do all the time.<br />
Of course, that previous paragraph is making the assumption that developers want to make things easier for themselves. I specialize in tool-building, in making it easier for my co-workers and myself to complete tasks. Some developers like "job security", though. They don't want to build on their skills because doing so raises expectations. They don't want to make it easier to do tasks because doing so raises expectations. They don't want to make it easier for others to do the task because doing so reduces demand. In maintaining low expectations, these developers have allowed themselves to remain gainfully employed while stagnating developmentally.<br />
<br />
<blockquote>
make a bunch of simple stuff terribly complex.</blockquote>
This appears to be the proof of stagnation. Any developer truly interested in growth will realize the shortcomings of his own tools. You design a tool to do the best you can possible design it to do and, down the road, realize that you need it to do more or that you can make it work more efficiently. So you revisit your tool, apply lessons learned, and make it more powerful, more efficient, faster. This is as true of a developer working on his own tools as one who writes an IDE. C++ as a language has not changed significantly in the past few decades, but the compilers and libraries available for it have changed dramatically.<br />
<blockquote>Phone gap mobile apps just add to that.</blockquote> A ColdFusion developer is not <em>required</em> to build websites that double as mobile applications. With all the programming experience that I have, I still haven't written mobile applications or responsive websites. I have not been required to do so to this point. Would I like to? Yes! Am I terrified of it? To a certain extent. Why? Because I haven't done it yet. Treading into unfamiliar territory can be daunting, but it's the recluse who never steps out of his comfort zone because he's confronted with the vastness of the outside world.<br />
<br />
<blockquote>
CF should be simple, auto generate everything, and make all the jquery bs and the ajax that goes with it be behind the scenes.</blockquote>
Again, the disconnect between wanting a language that's easy to use and not wanting something that's object-oriented. ColdFusion does offer this. Compared to other languages, ColdFusion makes it super simple to make AJAX-enabled applications. You can generate an AJAX-enabled webpage without writing WSDL or any JavaScript using ColdFusion because of ColdFusion's UI tags. If the programming community is disgruntled with the quality of ColdFusion's implementation of these UI tags, the programming community has the same right to free speech that you have; if you don't want to hear it, you don't have to.<br />
<br />
<blockquote>
CF was once easy and simple and I could hire an 8th graded to code it, and it worked great.</blockquote>
<p>ColdFusion is still easy. ColdFusion is still simple. You can still hire an eighth-grader to code in it and they would probably do a better job of it. Why? Eighth-graders are still adventurous. Got a problem with your computer? Consult your nearest ten-year-old. They're not bound by the fences that most adults have built for themselves: "I don't understand this new-fangled technology." "I don't think it can do that." "I've tried going in there and I just can't understand it." "People will think I'm stupid if they see me reading the manual."</p>
<p>Let me put this a different way. When I first started with ColdFusion, I found the ColdFusion UI tags and used them. I liked how they simplified things. Then I wanted them to do something more or do something a little different. They disappointed. I ended up writing my own custom tags to simplify display, grouping, and aggregation of data in a grid. I wrote my own tab control and then revisited it to utilize the jQuery UI Tabs widget. I wrote my own custom tag to handle pagination. I started using the jQuery UI Dialog widget. I started with the ColdFusion UI tags and migrated as more was required.</p>
I have my qualms with ColdFusion and I'm not afraid to say that. I do take issue with developers who have lost the desire to continue improving themselves. I hope that such developers do not become the educators of future developers.Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-15338333135232293182014-03-08T20:27:00.002-08:002014-03-08T20:29:41.567-08:00The Imperative Programming Life<h2>Freedom Needs Fences</h2>
<p>Last year, I gave a presentation to a group of people regarding fences, both actual fences and metaphorical fences. What is the purpose of a fence? For many people in urban areas, fences silently tell us, "Do not trespass," or, "This is private property". In certain cases, particularly around construction sites, fences are a safety precaution: "Enter at your own risk." In rural areas, fences are often used to set aside a safe area, whether you're setting aside an area safe for your livestock or an area safe for your children. In certain cases, the "dangerous area" has an exclave inside your "safe area", such as a well, so you build a fence around it.</p>
<p>What's the point? Many people, particularly in the United States, have the impression that freedom means "no rules". Freedom means doing whatever you want whenever you want to do it. Is that true freedom? If we rid the world of all the rules and there were no legal consequences for any and all actions, what would happen? How long would it be before robbery and murder were again outlawed? How long would it take before people started developing their own rules of law again?</p>
<p>Freedom does not mean "no rules". True freedom means having just the right number of rules with the right amount of leeway to interpret them. What would we be saying if we removed the fence from around the well: "You are free to fall into the well and kill yourself." Would you do that if the well were fenced in your children's "safe area"?</p>
<p>Anyway, you get the gist. One of the other ideas that I presented were some of the metaphorical fences that we build for ourselves. How many of your day-to-day tasks do you do in a specific order and no other? Most pilots follow a checklist in a specific order and don't deviate from it. They do this to make sure that prerequisites are met, safety concerns are addressed, and everything is in order before they take off. When you get in the car, do you do things in a specific order? Have you made a mental checklist for getting into a car and for getting out of the car? These are metaphorical fences designed to prevent doing something potentially dangerous or costly, like driving without the seat belt engaged or forgetting to lock the door when we get out of the car.</p>
<h2>Morning Routine</h2>
<p>I am a morning person by training; I am a night owl by heritage. My parents were night owls, my brother and sister are night owls, and I usually stay up all night with them when we're all together. However, I have had to learn how to get up and operate in the morning and, by and large, I am usually required to get up in the morning. Gone are the days of sleeping until 5 p.m. like I would on Saturdays and Sundays during the college term. Gone are the summer days where I slept all day and studied Latin all night.</p>
<p>I understand the dangers studies pose about hitting the snooze button. When I was teaching myself to be a morning person, I also learned how to wake up and operate with the first alarm and try not to hit the snooze button. I've not been totally successful, but I wake up more completely and quickly than anyone else in my household on the weekdays. This essentially means that I am the driving force behind the family's morning routine, particularly in helping my son get ready for school.</p>
<p>You got it. There's a routine. There's a mental checklist. Believe me, if I do something out of order on that checklist, I've lost time trying to figure out where I am, what I've done, and what's left. I stick to that mental checklist because, if I deviate from it, my wife may not make it to work on time, my son may not make it to school on time, and I may not make it to work on time. I've built this elaborate, metaphorical fence to prevent those consequences.</p>
<h2>Metaphorical Wells</h2>
<p>Another metaphorical fence we sometimes build for ourselves crops up when we use complex machines, like household appliances and computers. The more complex the machine, the less most people tend to know about the available functionality. Do you understand all the ways you can operate your microwave oven? Does your stove do things you didn't know it could? When you use your word processing application, are there huge areas of functionality that you've never explored? Do you even know they're there?</p>
<p>I venture to say that most web programmers don't know all the tags available in HTML. Most CFML programmers don't know all the CF tags and functions available in that language. Don't worry: I've got three fingers pointing back at me and I know it. We've found what we need to get along and, to a certain extent, fenced off the rest until we're good and ready to explore those areas. Many programmers, comfortable with their knowledge of the language and uninspired to expand that knowledge, may never explore those areas.</p>
<p>Let's look at the well now. Are there portions of your word processing software that you used once upon a time and it didn't work correctly or didn't do what you expected it to do? Did you find a workaround and never try using those portions again? That's another fence. "The software says it can do that, but it's buggy, so I do this instead." Are there similar aspects of your language of choice that you avoid because you never got it to do what you expected it to do or it was broken?</p>
<h2>The Imperative Programming Life</h2>
<p>My son recently got on another of his stints watching the same movie repeatedly. This time, he was watching "WALL-E". On our way home from school, he was asking me some questions. There are three main characters who are computer-driven: WALL-E, EVE, and AUTO-PILOT (nicknamed "AUTO", which comes out sounding like "OTTO"). These characters and others in the movie are given "personality".</p>
<blockquote>
<p>My son asked me, "Why didn't AUTO want to go home?"</p>
<p>"AUTO was programmed not to go home."</p>
<p>"But the captain said it was ok. Was AUTO afraid to go home?"</p>
<p>"No, AUTO was programmed to obey commands. He was commanded not to go home. Remember: Computers are really stupid; they're just very good at following instructions."
<p>He then transitioned: "Why did WALL-E keep cleaning up?"</p>
<p>"That's what he was programmed to do."</p>
<p>"But there was nobody left. Why did he keep cleaning up?"</p>
<p>"Did someone tell him to stop?"</p>
<p>"No."</p>
<p>"Nobody told him to stop, so he didn't stop."</p>
</blockquote>
<p>Do you find yourself performing actions a particular way, in a particular order, hesitant to change because you're afraid of the consequences? Do you continue doing something, even when it doesn't seem necessary anymore, simply because you were never told to stop?</p>
<small>Credit goes at least partially to my father, Norman Rowe, for the "Computers are stupid..." quote. I don't know if he got it from someone else, but I got it from him.</small>Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0tag:blogger.com,1999:blog-2478483050222836396.post-57528802301010298052014-03-01T21:28:00.001-08:002014-03-01T21:35:06.209-08:00The Transition from a 9-to-5'erIn reading some other blogs written by other programmers, I realize that I have long been deserving of the term 9-to-5'er. In fact, I was aware of the symptoms long before I realized there was a term for it. I knew that I would only program when I was being paid to do it; I couldn't build up the motivation to do programming on my own.<br />
<br />
Did I lack interest in developing my own projects? No! It was simply a question of willpower. I couldn't make myself sit down and start something new nor could I find a project out there that I really wanted to work on.<br />
<br />
Here I am now. For more than a year, I have been designing a very complex application in my head. I set up CFWheels on my computer, I've got Resin running, and I even drew up some graphics. But the code for the application isn't coming. The ideas multiply, the database structure grows in complexity, but all of this remains vaporware.<br />
<br />
This is a business application that I want to develop. However, I am wanting to bring together two concepts that mesh nicely together. The one is this concept that employees enjoy working with business application software that feels like a game. The other is the Nurtured-Heart Approach, which encourages parents to reward (and discipline) their children in much the same way that a game does.<br />
<br />
I've also been working as a government contractor for more than a year. Government websites must be accessible to people with disabilities. So I find myself struggling with more questions. How do I make business application software look and feel like a game yet not sacrifice accessibility?<br />
<br />
I realized this week that, as with so many other things, I should start small and build from there. I won't work on my massive project yet. I will wait until I've gotten myself into the habit of developing at home.<br />
<br />
To that end and others besides, I will try to learn how to write HTML games. I may start by writing educational games, since I may have an audience for those already. I will learn how to write accessible, responsive websites, because some of the members of my audience are learning-different and many of them have mobile devices.<br />
<br />
Wish me luck in my transition. Hopefully, my blog won't die with but one entry.Anonymoushttp://www.blogger.com/profile/12717950777076253325noreply@blogger.com0