<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to Programming_Tips</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>Recent changes to Programming_Tips</description><atom:link href="https://sourceforge.net/p/xcat/wiki/Programming_Tips/feed" rel="self"/><language>en</language><lastBuildDate>Wed, 23 Dec 2015 05:32:46 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/xcat/wiki/Programming_Tips/feed" rel="self" type="application/rss+xml"/><item><title>Programming_Tips modified by XiaoPeng Wang</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v25
+++ v26
@@ -138,7 +138,7 @@

 Also you can use the command perltidy to format your code:

-    perltidy -w -syn -g -opt -i=4 -nt -io -nbbc -kbl=2 -pscf=-c -aws -pt=2 -bbc  &amp;lt;orig_code) -o="" &amp;lt;formatted_code=""&amp;gt;
+    perltidy -w -syn -g -opt -i=4 -nt -io -nbbc -kbl=2 -pscf=-c -aws -pt=2 -bbc -nolc  &amp;lt;orig_code&amp;gt; -o &amp;lt;formatted_code&amp;gt;

 Following is a piece of code to demo the recommended code style for xCAT.

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">XiaoPeng Wang</dc:creator><pubDate>Wed, 23 Dec 2015 05:32:46 -0000</pubDate><guid>https://sourceforge.netea1d4b663fe020f5117142fc908978bb7d221cc7</guid></item><item><title>Programming_Tips modified by XiaoPeng Wang</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v24
+++ v25
@@ -137,9 +137,11 @@
 Refer to the perl sytel doc: http://perldoc.perl.org/perlstyle.html

 Also you can use the command perltidy to format your code:
+
     perltidy -w -syn -g -opt -i=4 -nt -io -nbbc -kbl=2 -pscf=-c -aws -pt=2 -bbc  &amp;lt;orig_code) -o="" &amp;lt;formatted_code=""&amp;gt;

 Following is a piece of code to demo the recommended code style for xCAT.
+
 ~~~~
 #! /usr/bin/perl

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">XiaoPeng Wang</dc:creator><pubDate>Tue, 22 Dec 2015 06:17:20 -0000</pubDate><guid>https://sourceforge.net57a0f458747d0cb33e2e47ee266494a96bf905c0</guid></item><item><title>Programming_Tips modified by XiaoPeng Wang</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v23
+++ v24
@@ -134,7 +134,12 @@
     while (

 ## Code Style
-
+Refer to the perl sytel doc: http://perldoc.perl.org/perlstyle.html
+
+Also you can use the command perltidy to format your code:
+    perltidy -w -syn -g -opt -i=4 -nt -io -nbbc -kbl=2 -pscf=-c -aws -pt=2 -bbc  &amp;lt;orig_code) -o="" &amp;lt;formatted_code=""&amp;gt;
+    
+Following is a piece of code to demo the recommended code style for xCAT.
 ~~~~
 #! /usr/bin/perl

@@ -145,6 +150,7 @@
 use warnings;

 #--------------------------------------------------------------------------------
+
 =head3   subroutine_example
     Descriptions:
         This a subroutine to demo how to write perl code
@@ -156,6 +162,7 @@
         0 - success
         0 - fail
 =cut
+
 #--------------------------------------------------------------------------------
 sub subroutine_example {
     my ($param1, $param2, $param3) = @_;
@@ -185,11 +192,12 @@
 if (%a_local_hash and
     defined($a_local_hash{v1}) and
     defined($a_local_hash{v2}) and
-    defined($a_local_hash{v3}) ) {
+    defined($a_local_hash{v3})) {
+
     # Calculate the sum of values
     my $sum_of_values = $a_local_hash{v1}
-                      + $a_local_hash{v2}
-                      + $a_local_hash{v3};
+      + $a_local_hash{v2}
+      + $a_local_hash{v3};

     print "The sum of values: $sum_of_values.\n";
 }
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">XiaoPeng Wang</dc:creator><pubDate>Tue, 22 Dec 2015 06:16:25 -0000</pubDate><guid>https://sourceforge.neteb8f3f020c655da28b513d562a55262b72efe315</guid></item><item><title>Programming_Tips modified by XiaoPeng Wang</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v22
+++ v23
@@ -135,19 +135,79 @@

 ## Code Style

-### Use Space to Indent
-Always use 4 spaces to indent. Don't use tab. Which would mess up the code format after multiple changes.
-
-### Description for Subroutine 
-  * Every new added subroutine should have a description part to explain the 'purpose/parameters/return value' of itself.
-    #--------------------------------------------------------------------------------
-    =head3   send_msg
-          Invokes the callback with the specified message
-        Arguments:
-            request: request structure for plguin calls
-            ecode: error code. 0 for succeful.
-            msg: messages to be displayed.
-        Returns:
-            none
-    =cut
-    #--------------------------------------------------------------------------------
+~~~~
+#! /usr/bin/perl
+
+# This is a perl program example to demo the recommended
+# style to write perl code
+
+use strict;
+use warnings;
+
+#--------------------------------------------------------------------------------
+=head3   subroutine_example
+    Descriptions:
+        This a subroutine to demo how to write perl code
+    Arguments:
+        param1: The first parameter
+        param2: The second parameter
+        param3: The third parameter
+    Returns:
+        0 - success
+        0 - fail
+=cut
+#--------------------------------------------------------------------------------
+sub subroutine_example {
+    my ($param1, $param2, $param3) = @_;
+
+    print "In the subroutine subroutine_example.\n";
+
+    return 0;
+}
+
+
+# Declar variables
+my $a_local_scale;
+my @a_local_array;
+my %a_local_hash;
+
+$a_local_scale = 1;
+
+@a_local_array = ("a", "b", "c");
+
+%a_local_hash = (
+    "v1" =&amp;gt; 1,
+    "v2" =&amp;gt; 2,
+    "v3" =&amp;gt; 3,
+);
+
+# Demo how to check the key of hash
+if (%a_local_hash and
+    defined($a_local_hash{v1}) and
+    defined($a_local_hash{v2}) and
+    defined($a_local_hash{v3}) ) {
+    # Calculate the sum of values
+    my $sum_of_values = $a_local_hash{v1}
+                      + $a_local_hash{v2}
+                      + $a_local_hash{v3};
+
+    print "The sum of values: $sum_of_values.\n";
+}
+
+# Demo how to check whether the array is empty
+if (@a_local_array) {
+    print "Has element in array: " . join(',', @a_local_array) . "\n";
+}
+elsif ($a_local_scale) {
+    print "The value of a scale variable: $a_local_scale.\n";
+}
+else {
+    # None of above
+    print "Get into the default path.\n";
+}
+
+# Call the subroutine subroutine_example()
+subroutine_example($a_local_scale, \@a_local_array, %a_local_hash);
+
+exit 0;
+~~~~
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">XiaoPeng Wang</dc:creator><pubDate>Tue, 22 Dec 2015 05:50:53 -0000</pubDate><guid>https://sourceforge.net5485d7f19dfd2af2f356b80f4e3104bc0cb18ef1</guid></item><item><title>Programming_Tips modified by XiaoPeng Wang</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v21
+++ v22
@@ -133,3 +133,21 @@
     my @filecontent;
     while (

+## Code Style
+
+### Use Space to Indent
+Always use 4 spaces to indent. Don't use tab. Which would mess up the code format after multiple changes.
+
+### Description for Subroutine 
+  * Every new added subroutine should have a description part to explain the 'purpose/parameters/return value' of itself.
+    #--------------------------------------------------------------------------------
+    =head3   send_msg
+          Invokes the callback with the specified message
+        Arguments:
+            request: request structure for plguin calls
+            ecode: error code. 0 for succeful.
+            msg: messages to be displayed.
+        Returns:
+            none
+    =cut
+    #--------------------------------------------------------------------------------
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">XiaoPeng Wang</dc:creator><pubDate>Mon, 06 Jul 2015 03:15:23 -0000</pubDate><guid>https://sourceforge.netd39a5d03420273b1e0f9fac5d589f4591c1e6c5f</guid></item><item><title>Programming_Tips modified by Victor Hu</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v20
+++ v21
@@ -17,17 +17,17 @@

 If you just put a variable by itself in a boolean expression to check to see if the variable was assigned a value, you will get incorrect results if the variable was assigned "0". For example: 

-    my $stab = xCAT::Table-&amp;gt;new('site');
-    my $sent = $stab-&amp;gt;getAttribs({key=&amp;gt;'svloglocal'},'value');
-    if ($sent and $sent-&amp;gt;{value}) {
+    my $stab = xCAT::Table-&amp;gt;new('site');
+    my $sent = $stab-&amp;gt;getAttribs({key=&amp;gt;'svloglocal'},'value');
+    if ($sent and $sent-&amp;gt;{value}) {
         # this section will not get executed if svloglocal has the value "0", which is a value valid
     }

 Instead, it should be coded like this: 

-    my $stab = xCAT::Table-&amp;gt;new('site');
-    my $sent = $stab-&amp;gt;getAttribs({key=&amp;gt;'svloglocal'},'value');
-    if ($sent and defined($sent-&amp;gt;{value}) ) {
+    my $stab = xCAT::Table-&amp;gt;new('site');
+    my $sent = $stab-&amp;gt;getAttribs({key=&amp;gt;'svloglocal'},'value');
+    if ($sent and defined($sent-&amp;gt;{value}) ) {
         # blah, blah
     }

@@ -53,7 +53,7 @@
 Using **require** instead of **use** does mean that you have to fully qualify all references to functions or vars in the module, when referring to them from outside of the module. But this is good practice anyway, because it makes the code more self-documenting. (Normally, within the module it can refer to its own functions and variables w/o fully qualifying them.) There are 2 ways to fully qualify a reference to something in a module: 

     xCAT::NodeRange::noderange($range);
-    xCAT::Utils-&amp;gt;isLinux();
+    xCAT::Utils-&amp;gt;isLinux();

 The 1st form is normal function invocation semantics. The 2nd form will actually pass the class name as the 1st parameter into the function, which the function must be expecting or it will cause errors in your logic. In general, the 1st form is preferable, since it is simpler. The 2nd form should be used if the module can also be used in an object-oriented fashion, because then the class name or object is passed in as the 1st argument in both cases. 

@@ -74,22 +74,22 @@

 Doing "return 1;" from a plugin doesn't accomplish anything. The proper way is to do: 

-    push @{$rsp-&amp;gt;{errorcode}}, $someexitcode;
-    push @{$rsp-&amp;gt;{error}}, "my error message";
+    push @{$rsp-&amp;gt;{errorcode}}, $someexitcode;
+    push @{$rsp-&amp;gt;{error}}, "my error message";

 ## Client/server response structure

 A lot of our code isn't handling the response structure correctly. A lot of places seem to just be **incorrectly** setting, for example: 

-    $rsp-&amp;gt;{data}-&amp;gt;[0] = 'foo';    # wrong
+    $rsp-&amp;gt;{data}-&amp;gt;[0] = 'foo';    # wrong

-But this is only valid if you are sure no code has already put something in $rsp-&amp;gt;{data} . A **better** way is to do this is: 
+But this is only valid if you are sure no code has already put something in $rsp-&amp;gt;{data} . A **better** way is to do this is: 

-    push @{$rsp-&amp;gt;{data}}, 'foo';    # right
+    push @{$rsp-&amp;gt;{data}}, 'foo';    # right

 BTW, you can also put a whole list on to that array using push, instead of using a foreach loop: 

-    push @{$rsp-&amp;gt;{data}}, @myarray;
+    push @{$rsp-&amp;gt;{data}}, @myarray;

 ## GetOptions()

@@ -119,7 +119,7 @@
   * Try not to process a table multiple times for a single command. If you can use a single call to getNodesAttribs or getAllNodeAttribs and then loop thru the hash, do that. If for some reason you need to read the whole table (like with getAllAttribs(), read it into a hash and process the hash multiple times. 
   * Do not search an array using "grep(/something/, @arrayname)" if the array has more than several items, the performance of this code is very bad, especially in a large scale environment. Convert the array to a hash like: 

-    %nodehash = map { $_ =&amp;gt; 1 } @nodes;
+    %nodehash = map { $_ =&amp;gt; 1 } @nodes;

     If the above line of code is a mystery to you, here's what is happening: map takes each element of the array and evaluates what is in the braces and adds that to the list it is returning to the lefthand side of the equals. In this case, each element of the @nodes array gets converted to 2 elements, for example: node5, 1. So map returns a list like: node1, 1, node2, 1, node3, 1, etc. In perl, when an array/list is assigned to a hash, it takes every other element as a key, and the alternate elements as the values. 
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Victor Hu</dc:creator><pubDate>Thu, 02 Oct 2014 20:25:47 -0000</pubDate><guid>https://sourceforge.netd52042687cd03a2eecb23aabaf20ecffa5584c41</guid></item><item><title>Programming_Tips modified by Bruce</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v19
+++ v20
@@ -122,8 +122,8 @@
     %nodehash = map { $_ =&amp;gt; 1 } @nodes;

-    If the above line of code is a mystery, here's what is happening: map takes each element of the array and evaluates what is in the braces and adds that to the list it is returning. In this case, each element of the @nodes array gets converted to 2 elements in the list, for example: node5, 1. In perl, when an array (list) is assigned to a hash, it takes every other element as a key, and the alternate elements as the values. 
-    Now that you have a hash with a value of 1 associated with all keys, you can efficient check for the element with: 
+    If the above line of code is a mystery to you, here's what is happening: map takes each element of the array and evaluates what is in the braces and adds that to the list it is returning to the lefthand side of the equals. In this case, each element of the @nodes array gets converted to 2 elements, for example: node5, 1. So map returns a list like: node1, 1, node2, 1, node3, 1, etc. In perl, when an array/list is assigned to a hash, it takes every other element as a key, and the alternate elements as the values. 
+    Now that you have a hash with a value of 1 associated with all keys, you can efficiently check for the element with: 

     if ($nodehash{node5} == 1)

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bruce</dc:creator><pubDate>Mon, 23 Jun 2014 15:35:22 -0000</pubDate><guid>https://sourceforge.net4711b8c187d72779c3a85615a440cba51567ceb8</guid></item><item><title>Programming_Tips modified by Bruce</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v18
+++ v19
@@ -117,57 +117,19 @@

   * Always keep in mind that tables can be very large. Although our development clusters tend to be just a few nodes, one of the key strengths of xcat is that it can manage very large clusters. Don't read table entries one at a time. Use the fewest calls to routines in Table.pm as possible. This is why routines like getNodesAttribs and getAllNodeAttribs were created to be able to get attributes for multiple nodes in a single call. Much faster. 
   * Try not to process a table multiple times for a single command. If you can use a single call to getNodesAttribs or getAllNodeAttribs and then loop thru the hash, do that. If for some reason you need to read the whole table (like with getAllAttribs(), read it into a hash and process the hash multiple times. 
-  * Do not search an array using "grep(/something/, @arrayname)" if the array has more than several items, the performance of this code is very bad, especially in the scalability environment. Convert the array to hash like: %arr = (sth1=&amp;gt;1,sth2=&amp;gt;1,sth3=&amp;gt;1), then use "if ($arr{something} == 1)" to determine if the "something" is in the array. 
-  * Resolving a hostname to an ip address might take a long time because in some network configuration scenarios, like the name server is not responding or being overloaded or the /etc/hosts has a lot of hosts. Try to reduce the numbers of the converts between the hostnames and ip addresses. 
-  * In addition to structuring code well, always be thinking about performance. Is this operation in a loop that will be executed 1000's of times if we have 1000's of nodes? If so, pull the most time consuming parts outside of the loop. This is especially important in database access. And any time one of our xcat commands takes minutes to complete, we should be analyzing it to make it faster. Our goad should be for almost all of our commands to take seconds, not minutes, even on large clusters. 
-  * To structure the code for logic encapsulation, we can put details into a function so the callers of that function don't have to worry about the details. This is step 1 in good code structure, but only step 1. If this is a function that can be called often with a single xcat cmd request (e.g. within a loop for each node), then step 2 is analyzing the statements within the function to see which take a non-trivial amount of time and decide if it could be done just once outside the function, outside the calling loop. This is the case with getAllNodeAttribs inside getIPaddress. In this type of situation, for efficiency, you need to pull that operation outside the function so the caller can do it once (outside of the caller's loop), and pass the info into the function. This undoes a little of the nice clean encapsulation you did in step 1. Because of that you need to make it as clean and well documented as possible, so that other readers of the code can follow what had to be done to make it more efficient. In the case of getIPaddress, i would suggest a new optional argument called ppcattrs, which is a ptr to the array that getAllNodeAttribs returns. If it is passed in, then getIPaddress doesn't have to call getAllNodeAttribs itself. This way the caller can run getAllNodeAttribs once outside of its loop and pass a ptr to the array in. You may have to pass it thru several layers of functions, but it is still the right way to handle this situation. Just make sure you document (comment) the function arguments clearly at each level. 
-
-## Check Command Exit Codes
-
-Check exit codes from all commands run. Too many times xcat keeps running even after something has failed and then we don't give the user a clear error msg about the original thing that went wrong. On this topic, whenever you are putting an error msg in your code, think "what would i want to know if i was running this command and it failed and i had no idea why?" Put as many specific parameters in the error msg as possible w/o making it too long: node name, attribute value being used, command that returned an error, etc. 
-
-## Write Safeguarded Code
-
-When coding, constantly ask yourself "what could go wrong at this point" and safeguard against that in the code. A simple example is the recent problem found in confighfi in which it only runs ifup on the adapters, but didn't handle the case where they are already up, but configured incorrectly. (I'm not picking on the person who wrote this. There are tons of examples like this in xcat. This just happend to be the freshest in my mind.) Writing system mgmt code is different from other types of coding in that the code is not in a controlled, self-contained environment. The admin can change/mess up the environment thru many different outside commands and actions. When considering the safeguards, you also have to consider how slow the safeguard will be. If it will hurt performance you have to make a judgement and maybe find another way to safeguard. 
-
-## Constantly Improve Usability
-
-Any time you are setting a bug Resolution to Invalid or Rejected (which usually means user error), you should think about how the user made the mistake. Is our documentation not clear enough? Could the xcat code guard against this mistake? System admin of clusters is very complicated and xcat should be helping the admin to not only get things done quickly, but avoid mistakes. I've seen many bugs closed as user error, and though that is usually technically true, we should use the bug as an opportunity to make it less likely in the future that someone will make that same mistake. This is how we will improve the usability of xcat (a frequent complaint). 
-
-## Clear and Informative Error Messaages
-
-Clear and informative error msgs are one of the most important aspects of usability. Because it is at that exact point that users are having a problem, so they need our assistance more than ever. 
-
-We should have a constant focus on good error msgs when we are coding and when we are testing, and fix bad errors msgs on a case by case basis. fvt should consider a bad error msg to be a bug. Here are two examples of the bad error messages: 
+  * Do not search an array using "grep(/something/, @arrayname)" if the array has more than several items, the performance of this code is very bad, especially in a large scale environment. Convert the array to a hash like: 

-    1. The /tmp directory is not writable on the compute node rhcn1
-    [root@mn ~]# xdsh rhcn1 -e "/install/postscripts/dummyscript"
-    rhcn1: bash: /tmp/fileOMApve.dsh: No such file or directory
-    rhcn1: rm: cannot remove `/tmp/fileOMApve.dsh': No such file or directory
-    [root@mn ~]#
-    
-    
-    2. If the node hostname could not be resolved:
-    [root@mn ~]# nodeset osc osimage
-    osc: Error: Unable to find requested xcatmaster from noderes, with node=osc
-    Error: Some nodes failed to set up install resources, aborting
-    [root@mn ~]# 
-    
-    
-    3. If there is some typo in the node "mgt" attribute
-    [root@mn ~]# rpower oscn1 stat
-    oscn1: Error: Unable to identify plugin for this command, check relevant tables: nodehm.power,mgt
-    [root@mn ~]# 
+    %nodehash = map { $_ =&amp;gt; 1 } @nodes;

-Here are a few guidelines about errors msgs we should all keep in mind: 
+    If the above line of code is a mystery, here's what is happening: map takes each element of the array and evaluates what is in the braces and adds that to the list it is returning. In this case, each element of the @nodes array gets converted to 2 elements in the list, for example: node5, 1. In perl, when an array (list) is assigned to a hash, it takes every other element as a key, and the alternate elements as the values. 
+    Now that you have a hash with a value of 1 associated with all keys, you can efficient check for the element with: 
+    
+    if ($nodehash{node5} == 1)
+    

-  * Error msgs should be worded in terms of what the user is trying to do, not just about the exact problem that the code hit. In the 1st example above, instead of a msg saying "/tmp/fileOMApve.dsh: No such file or directory", it should be more like "error copying script dummyscript to node rhcn1 - creating file in directory /tmp failed". In the 2nd example above, it should say something like "can't resolve the hostname osc. Otherwise, the user doesn't have any idea on what is going wrong. 
-  * Error msgs should include the relevant data. In the 1st example above, it should include the file creation error string. In the 2nd rpower example above, it should display the value of mgt that it couldn't find a plugin for. 
-  * In general, try to think about this situation from the user's perspective, a user that is not an xcat expert. In the 3rd example above, the user probably has no idea that we use the mgt value to locate an xcatd plugin. So the error msg should just talk about "not a supported mgt value xxxx", instead of talking about plugins. 
-  * Every error condition should be checked and an error messages returned, if the first error condition is not checked and prompted, the subsequent errors will probably become worse and the error messages could not show what the original problem is. 
-  * Keep xCAT internals (e.g plugins) out of the messages, unless it is critical to debugging the problem. 
-  * Have each error message give as much information as possible, so the customer can debug the problem themselves. 
-  * Make them somewhat unique, so we can figure out where it came from in the code with a search. This is the one place that might make us think of numbered messages. 
-
-{{:Writing Man Pages}} 
+  * If you are reading an entire file into an array, do **not** do: 
+    
+    my @filecontent;
+    while (
+    
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bruce</dc:creator><pubDate>Mon, 23 Jun 2014 15:35:22 -0000</pubDate><guid>https://sourceforge.netb37ba00d0d3d08dc98acd6f400ed2eb939430c56</guid></item><item><title>Programming_Tips modified by Guang Cheng Li</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v17
+++ v18
@@ -166,5 +166,8 @@
   * Error msgs should include the relevant data. In the 1st example above, it should include the file creation error string. In the 2nd rpower example above, it should display the value of mgt that it couldn't find a plugin for. 
   * In general, try to think about this situation from the user's perspective, a user that is not an xcat expert. In the 3rd example above, the user probably has no idea that we use the mgt value to locate an xcatd plugin. So the error msg should just talk about "not a supported mgt value xxxx", instead of talking about plugins. 
   * Every error condition should be checked and an error messages returned, if the first error condition is not checked and prompted, the subsequent errors will probably become worse and the error messages could not show what the original problem is. 
+  * Keep xCAT internals (e.g plugins) out of the messages, unless it is critical to debugging the problem. 
+  * Have each error message give as much information as possible, so the customer can debug the problem themselves. 
+  * Make them somewhat unique, so we can figure out where it came from in the code with a search. This is the one place that might make us think of numbered messages.

 {{:Writing Man Pages}} 
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Guang Cheng Li</dc:creator><pubDate>Mon, 23 Jun 2014 15:35:21 -0000</pubDate><guid>https://sourceforge.net90597fb8868ef5866c22823b380979a7c5aad82d</guid></item><item><title>Programming_Tips modified by Guang Cheng Li</title><link>https://sourceforge.net/p/xcat/wiki/Programming_Tips/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v16
+++ v17
@@ -165,5 +165,6 @@
   * Error msgs should be worded in terms of what the user is trying to do, not just about the exact problem that the code hit. In the 1st example above, instead of a msg saying "/tmp/fileOMApve.dsh: No such file or directory", it should be more like "error copying script dummyscript to node rhcn1 - creating file in directory /tmp failed". In the 2nd example above, it should say something like "can't resolve the hostname osc. Otherwise, the user doesn't have any idea on what is going wrong. 
   * Error msgs should include the relevant data. In the 1st example above, it should include the file creation error string. In the 2nd rpower example above, it should display the value of mgt that it couldn't find a plugin for. 
   * In general, try to think about this situation from the user's perspective, a user that is not an xcat expert. In the 3rd example above, the user probably has no idea that we use the mgt value to locate an xcatd plugin. So the error msg should just talk about "not a supported mgt value xxxx", instead of talking about plugins. 
+  * Every error condition should be checked and an error messages returned, if the first error condition is not checked and prompted, the subsequent errors will probably become worse and the error messages could not show what the original problem is.

 {{:Writing Man Pages}} 
&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Guang Cheng Li</dc:creator><pubDate>Mon, 23 Jun 2014 15:35:21 -0000</pubDate><guid>https://sourceforge.net75b2c9b673ae7b7a467526639af38fd29e1665ba</guid></item></channel></rss>