AskJimBob
Shared work environments PDF Print E-mail
Written by Administrator   
Wednesday, 03 February 2010 07:18

I'm stepping out of my usual coding how-to here for a bit more of an education in the processes and procedures which make for a good shared work environment. If you haven't already been at a job or done work for a client where there is no standardization in coding techniques, life cycle processes or any formal development path, the consider yourself lucky. But what do you do when you *do* find yourself working in one of these environments?

My first inclination is to tell you to simply begin to implement the processes and procedures for everyone to use, but this rarely gains the support of senior staff who, for whatever reason(s), have yet to implement the required processes and procedures themselves. While I have been successful in the past at leveraging my experience to bring teams around to the ideas and concepts I'll outline below, I usually end up stepping on somebody's toes. A more practical way to implement this is to begin performing the processes and procedures yourself, and lead by example. When others on your team see how well commented your code is, that you have a revision system in place (if only on your own machine) and you ask pertinent questions during all parts of the life cycle then more often than not the rest of the team will come around to your way of thinking - especially when you're getting code changes made quickly and effectively while your peers do not.

Office politics aside, however, there are several key areas that you can focus on to improve any software engineering team, regardless of which development methodology is (or isn't) in place:

Adopt a methodology if one does not currently exist. If your team isn't using any specific development (life cycle) methodology then you've got your pick between several different methodology. The methodology most companies end up falling into is called the Waterfall methodology, and as it's name implies, the workload and goals tend to be rushed at every corner as clients expectations are usually never clearly defined. This happens mostly due to sales people promising the moon to clients to get their business with no real sense of how much effort or time it should take to accomplish a given task. Without a sales engineer on board, companies relying solely on sales to define requirements typically have a much longer development cycle, due to poorly defined requirements and frequent customer changes. This is a common problem among most small companies that have yet to embrace one of the myriad of methodologies available. Two of the most popular are CMMI and SCRUM. CMMI is an older methodology, tried and true, that defines a series of requirements for software development (and associated IT resources) and provides a means to evaluate where your organization does well and where it needs improvement in these processes. CMMI is typically used for longer-term development tasks (e.g. those that take months to complete) whereas SCRUM, a milestone based methodology, is better for shops that produce multiple small projects or use an application code base for multiple client sites (e.g. a content management system). I use both CMMI and SCRUM methodologies as I tend to h ave both small and large projects ongoing at any one time. CMMI provides a clear understanding of where your organization currently stands, and is a worthwhile evaluation exercise regardless of which methodology you ultimately choose.

Adopt a framework if one does not currently exist. Frameworks (such as model-glue, MachII, fuseBox and more for ColdFusion) provide structured methods for application development - providing a framework to work within. MVC frameworks are not always the best choice for every project or every organization, but are worth looking into as a means of streamlining your coding processes.

Create a Subversion server, if one does not already exist. Subversion, formally CVS, is an open source file versioning system similar in capabilities to those of Microsoft's Visual SourceSafe or Borland's StarTeam. It provides a repository for storing code, versioning files as they change and allowing for multiple functions including code merging, patch creation, locking and access controls, among many others. I use Visual SVN Server for my Windows based development, and the subversion server included with most linux distro's for my linux based development. For my SVN client, I prefer TortoiseSVN, and the built in subversion clients in Adobe products such as Dreamweaver (tho since SVN 1.5 Dreamweaver CS 4 no longer works), Coldfusion Builder, Flash Builder and most other Eclipse based IDE's. In a multi-developer environment, especially in one without coding standards, a versioning system is an absolute must and will save you hours of pulling out your hair manually merging code from other developers.

Adopt coding standards if they don't already exist. There are literally dozens of blog posts on the topic of coding standards for every programming language in the world. A coding standard simply states how you will write code consistently so that all your code is easy to read, easy to follow, is highly commented and can be easily picked up by any other developer and modified with little or no input from you. Using standardized coding techniques such as those outlined by core ColdFusion developers like Dan Wilson, Ray Camden, Ben Forta and others can simplify development tasks you undertake, and again serve as an example to other members on your team. Coding standards are probably the most important and significant changes any organization can make as they clearly define how all developers should write code within the organization.

Refactor code as you go. We've all written completely complex, totally misguided code at some point in our careers, and as you progress you get to see this mistake repeated time and time again by more junior engineers (and sometimes even the senior ones!). Part and partial the process of upgrading or modifying any code should be refactoring any and all code that should be refactored as you go. Now while not all projects or organizations can afford the time to completely refactor any application in a single go - multiple refactorings over time will improve the application, shorten future development time, and optimize the applications for clients.

Reuse duplicate code. As applications develop you'll find that you tend to use a lot of the same code in multiple places. This is especially true of database intensive applications which make use of the same (or very similar) database queries over and over again. Write components (CFC's) for as many of these duplicate code block as you can and make use of the components. This will reduce your application size, reduce your file size, centralize the code used by multiple pages and make your code easier to read and understand.

Standardize databases always, Normalize databases only where needed. I see this mistake *all* the time. In an effort to provide the most capabilities and functionality for applications... developers, especially those that are not DBAs, tend to go too far when normalizing their databases. A good rule of thumb is, if you're not likely to have more than 1000 repeating records in a table (e.g. a user with multiple entries in an access control list) then don't normalize the table. I know a lot of people are going to be upset with me for saying that, as best practices suggest that you should normalize everything, regardless of how many records are being stored. But, in real world development, especially in fast paced or under-staffed environments, normalizing is a profit killer. Standardizing database structure is another key element and goes hand in hand with coding standards (and, typically, are included in most coding standards documents). In multi-developer environments you'll easily find databases being created and extended in a myriad of ways using a myriad of schema's depending on the individual developers own experience. You'll find table names and field names a mixed variety of lowercase and uppercase, camel case and headless camel case, and an equally distinct set of field types and values. Standardizing the way databases are developed and extended will eliminate these problems and more often than not reduce the amount of code required to mashup the different tables.

To learn more about these and other topics, be sure to attend our next NVCFUG meeting on Feb 16th, 2010 from 7-9pm in Farifax, VA (Full details and RSVP)

 

 

Last Updated on Wednesday, 03 February 2010 08:47
 
The ways of bits and bytes: Part I PDF Print E-mail
User Management
Written by Denny Springle   
Wednesday, 06 May 2009 07:19

Coldfusion takes a byte!
Coldfusion developers have the ability to do some 'old school' style binary development with the BitAnd, BitOr, BitNot and BitXOr logical bit functions, along with the BitSHLN, BitSHRN, BitMaskSet, BitMaskRead and BitMaskClear functions.

In this article we'll explore the use of BitAnd and a 32-bit long byte for manipulation of access controls. For the uninitiated, however, let's have a first look at bits and bytes.

What is a bit and a byte?
A bit is a single boolean true (1) or false (0) part of a larger structure known as a byte. The bit position and value within a string of bits (e.g. a byte) determine the total value of that byte. Each bit can have a logical (true/false) value of 1 or 0. Bit position affects the value of the byte, starting from the right with a value of 1, and with each bit in the byte multiplied of the previous bit by two as you move left. This is best illustrated with examples:

Example 1

Let's look at the simplest byte, made up of only two bits. The rightmost bit, with a positional value of 1, the leftmost bit with a positional value of 2 (1*2). This two-bit byte has four possible combinations:

00 = Zero. No bit positions are set, so the value remains zero.
01 = One. Since the rightmost bit position has a value of 1, and the rightmost bit is set true (1) while the leftmost bit is set false (0), the byte has a value of 1.
10 = Two. Since the leftmost bit position has a value of 2, and the leftmost bit is set true (1) while the rightmost bit is set false (0), the byte has a value of 2.
11 = Three. Huh? This is where most people begin to get confused. Since the leftmost bit position has a value of 2 (1*2) and is set true (1) and the rightmost bit position has a value of 1 and is also set true (1), they are added together and the byte has a value of 3.

 

Example 2

Now let's look at the next simplest byte, made up of four bits (bytes are almost always an even number of bits for the purpose of web development discussions - bits at the hardware level behave a bit differently (pardon the pun), and are frequently odd-numbered). In this case, the positional values of the rightmost bit is still 1 (always), the second bit (from the right) retains it's positional value of 2 (1*2). The next bit over, third from the right, has a positional value of 4 (2*2), and the leftmost bit (fourth from the left) has a positional value of 8 (4*2). This byte has 16 possible combination's:

BinaryHexadecimal
DecimalPositional Math
 0000 0 00 (0 + 0 + 0 + 0)
 0001 1 01 (0 + 0 + 0 + 1)
 0010 2 02 (0 + 0 + 2 + 0)
 0011 3 03 (0 + 0 + 2 + 1)
 0100 4 04 (0 + 4 + 0 + 0)
 0101 5 05 (0 + 4 + 0 + 1)
 0110 6 06 (0 + 4 + 2 + 0)
 0111 7 07 (0 + 4 + 2 + 1)
 1000 8 08 (8 + 0 + 0 + 0)
 1001 9 09 (8 + 0 + 0 + 1)
 1010 A 10 (8 + 0 + 2 + 0)
 1011 B 11 (8 + 0 + 2 + 1)
 1100 C 12 (8 + 4 + 0 + 0)
 1101 D 13 (8 + 4 + 0 + 1)
 1110 E 14 (8 + 4 + 2 + 0)
 1111 F 15 (8 + 4 + 2 + 1)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

As you continue to move the bit position left, the positional value continues to double the previous value. In this way, an eight bit byte has positional values, from right to left, of 1, 2, 4, 8, 16, 32, 64 and 128:

1
 11
1
1
1
1
 1
 128 64 32 16 8 42
 1

 

Telling the truth

With binary you're dealing with a boolean value or true (1) or false (0). In this way, bit manipulation deals with truth - what is true about this bit in this byte in comparison to another bit, usually. There are multiple good articles on truth tables online so I will not get into all of them here, however I will illustrate the logical AND and logical OR operations.

Logical AND operations compare two boolean values and return true only if the comparison is true, in other words, only if the same bit is true in each byte being compared. So, logical AND only returns true when both truths being tested are also true, producing the following truth table:

TRUTH 1
TRUTH 2
RESULT
 T T T
 T F F
 F T F
 F F F


Logical OR operations also compare two boolean values, however only return true is the comparison is false, in other words, only if the same bit is false in each byte being compared. So, logical OR only returns true when both truths being tested are false, producing the following truth table:

TRUTH 1
TRUTH 2
RESULT
 T T F
 T F F
 F T F
 F F T

 

 

Putting it in code
The following source code demonstrates how to utilize BitAnd for access control systems - storing up to 32 simultaneous access levels per user. An example of this code in action can be accessed at:

http://askjimbob.com/coldfusion_demo_code/using_bit_based_access_control.cfm

<!---
Name:            using_bit_based_access_control.cfm
Author:            Denard Springle ( This e-mail address is being protected from spambots. You need JavaScript enabled to view it )
Description:     Demonstrate using binary objects and bit manipulation
Created:        05/06/2009
License:        Creative Commons Attribution-Non Commercial 3.0
--->
<!--- initialize a string to hold the binary representation of our 32-bit zero byte --->
<cfset zeroByte = "">
<!--- initialize the zero byte --->
<cfset zeroByte = RepeatString('0',32)>
<!--- set up a row color variable to alternate colors --->
<cfset rC = 0>
<!--- set up a table to output the progress and results of this operation --->

<h1>32 Bit Combinations</h1>
<p>The following table represents the 32 bit positions available in a 32-bit byte. By using these positions you can assign up to 32 access control levels to the same user without depending on role lists (i.e. IsUserInRole() style). Storage and processing of a single 32-bit byte is demonstrated here in it's most basic form for easy digestion, however the use of single 32-bit byte is an optimal mathmatic calculation and storage method for tiered access controls.</p>
<table cellpadding="2" cellspacing="0" width="50%">
  <tr>
    <th style="text-align:center;">Bit Pos</th>
    <th style="text-align:center;">Bin Val</th>
    <th style="text-align:center;">Dec Val</th>
    <th style="text-align:center;">Hex Val</th>
  </tr>
  <!--- set up the first row (of zero's) --->
  <tr style="background-color:#FFFFEE;">
    <td style="text-align:center;">0</td>
    <td style="text-align:center;">[<cfoutput>#zeroByte#</cfoutput>]</td>
    <td style="text-align:center;">0</td>
    <td style="text-align:center;">0</td>
  </tr>
  <!--- create a new structure to hold the access controls --->
  <cfset thisStruct = StructNew()>
  <!--- put the zero byte in the structure (for later use) --->
  <cfset structInsert(thisStruct, 'this0', zeroByte)>
  <!--- loop through the 31 assignable bits (e.g. excluding zero [0]) --->
  <cfloop from="1" to="31" index="iX">
    <!--- initialize a string to hold the binary representation of our 32-bit byte --->
    <cfset binaryByte = "">
    <!--- set the current column to 32 bits minus the current index of iX, so, bit 31, 30, 29, etc. --->
    <cfset thisCol = 32-iX>
    <!--- loop through the zero bits which make up the beginning (left) of this byte (e.g. thisCol value) --->
    <cfloop from="1" to="#thisCol#" index="iY">
      <!--- add this bit positions false (0) bit to the byte string --->
      <cfset binaryByte = binaryByte & '0'>
      <!--- loop through the remaining begininng (left) bit positions that are zero --->
    </cfloop>
    <!--- add this bit positions true (1) bit --->
    <cfset binaryByte = binaryByte & '1'>
    <!--- init remaining columns --->
    <cfset newCol = 32-(thisCol+1)>
    <!--- check if we're at the last element in the list --->
    <cfif newCol GT 0>
      <!--- loop through and pad the right with zero (0) --->
      <cfloop from="1" to="#newCol#" index="iZ">
        <!--- add a zero (1) to the binary string --->
        <cfset binaryByte = binaryByte & '0'>
        <!--- loop through the rest of the padded zero's --->
      </cfloop>
      <!--- end checking if we're at the last element --->
    </cfif>
    <!--- put this byte in the structure (for later use) --->
    <cfset structInsert(thisStruct, 'this#iX#', binaryByte)>
    <cfif rC EQ 0>
      <cfset rowCol = "##DDDDEE">
      <cfset rC = 1>
      <cfelse>
      <cfset rowCol = "##FFFFEE">
      <cfset rC = 0>
    </cfif>
    <!--- output the current bit position and byte values to the screen --->
    <cfoutput>
      <tr style="background-color:#rowCol#;">
        <td style="text-align:center;">#iX#</td>
        <td style="text-align:center;">[#binaryByte#]</td>
        <td style="text-align:center;">#InputBaseN(binaryByte,2)#</td>
        <td style="text-align:center;">#FormatBaseN(InputBaseN(binaryByte,2),16)#</td>
      </tr>
    </cfoutput>
    <!--- loop through the rest of the possible byte values --->
  </cfloop>
  <!--- end the table --->
</table>
<br>
<br>
<!--- dump the structure --->
<h1>The structure</h1>
<cfdump var="#thisStruct#">
<br>
<br>
<h1>The Test Case</h1>
<p>In this test case we are going to add existing members of the structure (bytes) together. By adding these bytes together and then converting back to base 2 (binary) output you will see how multiple levels could be assigned to the same user.</p>
<!--- create a test case by adding together random bits from the 31 bytes created and stored in the structure --->
<cfset testCase = InputBaseN(structFind(thisStruct, 'this11'),2) + InputBaseN(structFind(thisStruct, 'this16'),2) + InputBaseN(structFind(thisStruct, 'this19'),2) + InputBaseN(structFind(thisStruct, 'this2'),2)>
<!--- initialize an output string --->
<cfset testCaseOutput = "">
<!--- loop through the missing begining (left) zero bit's --->
<cfloop from="1" to="#32-Len(FormatBaseN(testCase,2))#" index="iX">
  <!--- add the missing zero bits --->
  <cfset testCaseOutput = testCaseOutput & '0'>
  <!--- loop through the rest of the zero bit's --->
</cfloop>
<!--- set the output string to the zero's concantenated with the binary output of the test case --->
<cfset testCaseOutput = testCaseOutput & FormatBaseN(testCase,2)>
<!--- initalize a role list to capture the role names --->
<cfset roleList = "">
<table cellpadding="2" cellspacing="0">
  <tr>
    <th style="text-align:center;">Test Case Binary</th>
    <th style="text-align:center;">Test Case Decimal</th>
    <th style="text-align:center;">Current Bit Binary</th>
    <th style="text-align:center;">Current Bit Decimal</th>
    <th style="text-align:center;">Result</th>
  </tr>
          <tr style="background-color:#FFDDDD;">
          <td style="text-align:center;">[<cfoutput>#testCaseOutput#</cfoutput>]</td>
          <td style="text-align:center;"><cfoutput>#testCase#</cfoutput></td>
          <td style="text-align:center;">[<cfoutput>#structFind(thisStruct, 'this0')#</cfoutput>]</td>
          <td style="text-align:center;"><cfoutput>#InputBaseN(structFind(thisStruct, 'this0'),2)#</cfoutput></td>
          <td style="text-align:center;">False</td>
        </tr>
  <!--- loop through the 31 bytes in the structure --->
  <cfloop from="1" to="31" index="iX">
    <!--- output the current test byte itteration (iX) information --->
    <cfoutput>
      <!--- perform BitAnd against the current byte (iX) and the testCase byte --->
      <cfif BitAnd(InputBaseN(structFind(thisStruct, 'this#iX#'),2),testCase)>
        <!--- if BitAnd returns true, then the bit represented by the current byte (iX) is present in the testCase byte --->
        <tr style="background-color:##BBFFBB;">
          <td style="text-align:center; border-left:1px solid ##000000; border-top:1px solid ##000000; border-bottom:1px solid ##000000;">[#testCaseOutput#]</td>
          <td style="text-align:center; border-top:1px solid ##000000; border-bottom:1px solid ##000000;">#testCase#</td>
          <td style="text-align:center; border-top:1px solid ##000000; border-bottom:1px solid ##000000;">[#structFind(thisStruct, 'this#iX#')#]</td>
          <td style="text-align:center; border-top:1px solid ##000000; border-bottom:1px solid ##000000;">#InputBaseN(structFind(thisStruct, 'this#iX#'),2)#</td>
          <td style="text-align:center;  border-top:1px solid ##000000; border-bottom:1px solid ##000000; border-right:1px solid ##000000;">True</td>
        </tr>
        <!--- set the value of this byte in the role list --->
        <cfset roleList = ListAppend(roleList,structFind(thisStruct, 'this#iX#'))>
        <!--- otherwise, BitAnd returned false, so the bit represented by the current byte (iX) is *not* present in the testCase byte --->
        <cfelse>
        <tr style="background-color:##FFDDDD;">
          <td style="text-align:center;">[#testCaseOutput#]</td>
          <td style="text-align:center;">#testCase#</td>
          <td style="text-align:center;">[#structFind(thisStruct, 'this#iX#')#]</td>
          <td style="text-align:center;">#InputBaseN(structFind(thisStruct, 'this#iX#'),2)#</td>
          <td style="text-align:center;">False</td>
        </tr>
      </cfif>
      <!--- end checking current test byte --->
    </cfoutput>
    <!--- loop through to the next byte --->
  </cfloop>
</table>
<br>
<br>
<h1>The result</h1>
<p>Listed below are the binary roles detected by the BitAnd checking routine.</p>
<!--- output the roles randomly picked --->
<cfoutput>#roleList#</cfoutput> 

 

In Part II of this series I will break this down further into a component that can be used for level validation within your applications.

Last Updated on Wednesday, 13 May 2009 07:40