Friday, October 29, 2010
Four Steps
Spend less than you earn.
Spending less than you earn is very similar to another simple rule many struggle with when overweight:
Eat less than you burn.
Health and wealth and happiness are very inter-related. Getting control of your health can help you to get control of other areas of your life. Taking control of my eating habits helped me break away from other bad behaviors and get my financial situation under control.
With any change in life, you start by learning, then setting goals, making a plan to achieve them, and acting on your plan. The last step is critical, never wait to act. So learn what you should learn, get a plan for your goal, and GO!
1 Learn
You have to learn a better way, you can't keep doing the same thing and expect a different outcome. Learn what to do. For example, don't buy a gym membership and never learn how to safely exercise because you may hurt yourself and be worse off than before. Similarly, you should research budget plans or debt elimination strategies and pick one that you firmly believe will work for you, one that people like you have been successful with. This is also a time to get motivated and inspired by others who have been successful at making the change you are making. Finally, write a list of what benefits you will have from making the change (or start with this list), but keep it handy.
2 Goal != Dream
Good goals should be a specific and small, they should be steps on your journey toward your dreams and desires, their should be a deadline or target date for your goal. A dream to be a millionaire is not a goal. Good example of a goal would be to lose 10 lbs by December 2010, or pay off all credit card balances before July 2011.
3 Plan
Very important third step is to plan, be aware of your life and the obstacles you already have to accomplishing your goal, account for those in your plan. Some unexpected obstacles will blindside you, you may get pregnant, you may have a huge unexpected expense, or experience a job loss. Things happen that are out of your control and can impede your progress, expect them to happen but realize they happen to EVERYONE, and realize obstacles happened to people who were still successful with their goals. Decide to be one of those people, the ones that didn't give up or give in to challenges. Use the knowledge you gained to make a detailed plan. Keep in mind that your plan should not be unreasonable, your plan should be actually physically possible for you to do 100% of the time. Your plan should make sense to you, you need to believe that following the plan will work, not just hope that it will.
4 Act
Make a commitment to accomplish your goal with your plan. Think no-matter-what-I-am-doing-this, then as you act, no-matter-what, do it, stay committed. Decide now that you will always decide to go on, then never change your mind about it. You have to be a stubborn, hard-nosed jerk about it, because excess fat and debt are stubborn hard-nosed jerks too. Use the inspiration and motivation from other successful people to support you and help you to avoid falling backwards into addictive behaviors that take you away from your goal. If you look, you can find inspirational stories from people who had challenges accomplishing the very same thing you are trying to accomplish. Keep at it until you see movement, until you see a change you really are proud of, until you reach that goal, then immediately start over with step one and do it again. Don't bask in your awesomeness for a second, because that's a great time for an old behavior to creep back into your life. You achieved something, it felt great, it was great, don't ruin it by undoing that hard work.
Tuesday, September 14, 2010
Tynt programming assignment (Part 5)
As you can see, I re-used the IntegerList collection in the Hash collection. Since I am not sorting the IntegerList, I have to iterate through the entire key IntegerList to check for a key in the hash, with a sorted key IntegerList, I could short circuit after the key was larger than the sorted key it was compared with. I am also not implementing a hash algorithm at all, so the collection was not named very well. Implementing a true hash collection was not part of the assignment so I didn't worry about it.package com.tynt.app.util;
public class IntegerHash {
public static final int BUFFER_SIZE = 100;
private IntegerList values;
private IntegerList valueCounts;
public IntegerHash() {
values = new IntegerList();
valueCounts = new IntegerList();
}
public boolean hasInteger(Integer value) {
if (value == null) {
return false;
}
for(int i=0;i < values.size();i++) {
if (values.get(i).compareTo(value) == 0) {
return true;
}
}
return false;
}
public Integer getIntegerCount(int index) {
return valueCounts.get(index);
}
public Integer getIntegerIndex(Integer value) {
for(int i=0;i < values.size();i++) {
if (values.get(i).compareTo(value) == 0) {
return i;
}
}
return -1;
}
public void incrementIntegerCount(Integer value) {
int integerIndex = getIntegerIndex(value);
valueCounts.put(integerIndex, getIntegerCount(integerIndex)+1);
}
public void addInteger(Integer value) {
if (!hasInteger(value)) {
values.concatenate(value);
valueCounts.concatenate(1);
} else {
incrementIntegerCount(value);
}
}
public IntegerList getIntegers() {
IntegerList vals = new IntegerList();
for(int i = 0; i < values.size(); i++) {
vals.concatenate(values.get(i));
}
return vals;
}
public Integer getIntegerFrequency(Integer value) {
if (hasInteger(value)) {
int index = getIntegerIndex(value);
return getIntegerCount(index);
} else {
return 0;
}
}
}
Here is assignment5 using the above collection:
Finally, with all of the Assignment objects implemented and the tests passing, I can implement the Driver for the project:package com.tynt.app;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.tynt.app.util.*;
public class Assignment5 implements InputReader {
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
IntegerHash unsortedHash = new IntegerHash();
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
unsortedHash.addInteger(value);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
IntegerList sortedList = IntegerList.quicksort(unsortedHash.getIntegers());
if (sortedList == null) {
sortedList = new IntegerList();
}
for (int i=0;i < sortedList.size();i++) {
sb.append(sortedList.get(i));
sb.append(" - ");
sb.append(unsortedHash.getIntegerFrequency(sortedList.get(i)));
sb.append(NEW_LINE);
}
return sb.toString();
}
}
It is a bit confusing that I named the method's doAssignment2 and doAssignment3 but use Assignment4 and Assignment5 objects. I should have named these assignment classes better. Again it was a small programming assignment, and an easy refactor. Overall, I do think I did a decent job with this assignment and benefitted from the effort.package com.tynt.app;
import java.io.*;
import com.tynt.app.util.*;
/**
* Tynt programming challenge
*
* @author Four Gables Guy
*
*/
public class App {
public static final String header = "********************";
public static void main(String[] args) throws IOException {
String choice = displayChoices();
while (choice.equals("1") || choice.equals("2") || choice.equals("ALL")) {
parseChoice(choice);
if (choice.equals("ALL")) {
break;
}
choice = displayChoices();
}
}
public static void parseChoice(String choice) throws IOException {
if (choice.equals("1")) {
doAssignment2();
} else if (choice.equals("2")) {
doAssignment3();
} else if (choice.equals("ALL")) {
doAssignment2();
doAssignment3();
}
}
public static String displayChoices() {
System.out.println(header);
System.out.println("Enter 1 to parse " + InputReader.INPUT_FILE
+ " and print numbers sorted ascending.");
System.out.println("Enter 2 to parse " + InputReader.INPUT_FILE
+ " and print numbers sorted ascending.");
System.out.println("Enter any other characters to quit.");
System.out.println(header);
Console console = System.console();
if (console == null) {
return "ALL";
} else {
String line = console.readLine();
line = line.trim();
return line;
}
}
public static void doAssignment2() throws IOException {
Assignment4 assignment4 = new Assignment4();
FileInputStream is = new FileInputStream(new File(
InputReader.INPUT_FILE));
System.out.println(assignment4.readFile(is));
}
public static void doAssignment3() throws IOException {
Assignment5 assignment5 = new Assignment5();
FileInputStream is = new FileInputStream(new File(
InputReader.INPUT_FILE));
FileOutputStream os = new FileOutputStream(new File(
InputReader.OUTPUT_FILE));
String output = assignment5.readFile(is);
System.out.println(output);
os.write(output.getBytes());
os.flush();
os.close();
}
}
I created a handy batch file to execute the code called tynt.bat which does this:
java -cp target\program_assignment-1.0-SNAPSHOT.jar com.tynt.app.App
Monday, September 13, 2010
Tynt programming assignment (Part 4)
IntegerList implements a quicksort method which returns the IntegerList as a sorted IntegerList. My implementation of quicksort has several drawbacks:package com.tynt.app.util;
public class IntegerList {
public static final int BUFFER_SIZE = 100;
private Integer[] internalArray;
private int size;
public IntegerList() {
internalArray = new Integer[BUFFER_SIZE];
size = 0;
}
public IntegerList(int size) {
if (size < 0) {
throw new RuntimeException("Cannot create IntegerList with negative size");
}
internalArray = new Integer[size];
size = 0;
}
public int size() {
return size;
}
public void put(int index, Integer value) {
if (index > -1 && index < size) {
internalArray[index] = value;
} else {
throw new RuntimeException("Cannot put value "+value+" at index "+index+" IntegerList has size "+size);
}
}
public void concatenate(Integer value) {
if (value == null) {
throw new RuntimeException("Cannot concatenate null values");
}
if (size + 1 == internalArray.length) {
Integer[] temp = new Integer[internalArray.length + BUFFER_SIZE];
System.arraycopy(internalArray, 0, temp, 0,
internalArray.length);
internalArray = temp;
}
internalArray[size++] = value;
}
public void concatenate(IntegerList values) {
for (int i = 0 ; i < values.size(); i++) {
concatenate(values.get(i));
}
}
public Integer get(int index) {
if (index > -1 && index < size) {
return internalArray[index];
} else {
throw new RuntimeException("Cannot access value at "+index+" in IntegerList size "+size);
}
}
public Integer remove(int index) {
if (index > -1 && index < size) {
Integer result = get(index);
IntegerList integerList = new IntegerList();
for(int i = 0; i < size; i++) {
if (i != index) {
integerList.concatenate(get(i));
}
}
internalArray = integerList.internalArray;
size = size - 1;
return result;
} else {
throw new RuntimeException("Cannot access value at "+index+" in IntegerList size "+size);
}
}
public static IntegerList quicksort(IntegerList unsorted) {
IntegerList less = new IntegerList();
IntegerList greater = new IntegerList();
if (unsorted.size() <= 1) {
return unsorted;
}
Integer pivot = selectPivot(unsorted);
for(int i = 0; i < unsorted.size(); i++) {
Integer value = unsorted.get(i);
if (value <= pivot) {
less.concatenate(value);
} else {
greater.concatenate(value);
}
}
return concatenate(quicksort(less), pivot, quicksort(greater));
}
public static Integer selectPivot(IntegerList unsorted) {
if (unsorted == null || unsorted.size() < 2) {
throw new RuntimeException("Cannot select pivot on empty or single element list");
}
int pivotIndex = unsorted.size() / 2;
return unsorted.remove(pivotIndex);
}
public static IntegerList concatenate(IntegerList less, Integer pivot, IntegerList greater) {
if (less == null | pivot == null || greater == null) {
throw new RuntimeException("Cannot concatenate null values");
}
IntegerList finalList = new IntegerList(less.size()+1+greater.size());
finalList.concatenate(less);
finalList.concatenate(pivot);
finalList.concatenate(greater);
return finalList;
}
}
- I create additional collections (less,greater,etc...) for each invocation of quicksort and concatenate, so lots of memory could be used up with a long list to sort. It would be less memory to sort the list in-place without recursion/extra collections.
- Speaking of recursion, too much recursion could cause a stack overflow as well.
Still need to implement the Hash collection and driver.package com.tynt.app;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.tynt.app.util.*;
public class Assignment4 implements InputReader {
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
IntegerList unsortedList = new IntegerList();
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
unsortedList.concatenate(value);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
IntegerList sortedList = IntegerList.quicksort(unsortedList);
if (sortedList == null) {
sortedList = new IntegerList();
}
for (int i=0;i < sortedList.size();i++) {
sb.append(sortedList.get(i));
sb.append(NEW_LINE);
}
return sb.toString();
}
}
Sunday, September 12, 2010
Tynt programming assignment (Part 3)
src\main\java\com\tynt\app
called
com.tynt.app
Then right clicking the empty package and creating new Class (Assignment1) adding the InputReader interface to the class and stubbing out the interface method:
public String readFile(InputStream is) {
return null;
}
Just so you know.
For Assignment1 I just wanted to get the code for reading and creating a string from the input stream working:
For Assignment2 I decided to use the built-in Java collections classes to test what the output of my custom collection should look like:package com.tynt.app;
import java.io.*;
import com.tynt.app.util.InputReader;
public class Assignment1 implements InputReader {
/**
* @return contents of the InputStream as a String
*/
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb = new StringBuilder();
try {
line = d.readLine();
while (line != null) {
sb.append(line);
sb.append(NEW_LINE);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return sb.toString();
}
}
Again with Assignment3, I used built-in collections to check what the output should be for the histogram:package com.tynt.app;
import java.io.*;
import java.util.*;
import com.tynt.app.util.InputReader;
public class Assignment2 implements InputReader {
/**
* @return is list of numbers sorted in ascending order
*/
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
SortedSetsortedList = Collections.synchronizedSortedSet(new TreeSet ());
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
sortedList.add(value);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
for(Integer i: sortedList) {
sb.append(i);
sb.append(NEW_LINE);
}
return sb.toString();
}
}
Assignment4 and Assignment5 actually adhered to the restriction of no built-in collections.package com.tynt.app;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import com.tynt.app.util.InputReader;
public class Assignment3 implements InputReader {
/**
* @return sorted list of numbers and their frequency
*/
public String readFile(InputStream is) {
BufferedReader d = new BufferedReader(new InputStreamReader(is));
String line;
SortedMapsortedMap = Collections.synchronizedSortedMap(new TreeMap ());
try {
line = d.readLine();
while (line != null) {
Integer value = null;
try {
value = new Integer(Integer.parseInt(line));
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
Integer frequency = 1;
if (sortedMap.containsKey(value)) {
frequency = sortedMap.get(value);
frequency += 1;
}
sortedMap.put(value, frequency);
line = d.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
StringBuilder sb = new StringBuilder();
for(Integer key: sortedMap.keySet()) {
Integer frequency = sortedMap.get(key);
sb.append(key);
sb.append(" - ");
sb.append(frequency);
sb.append(NEW_LINE);
}
return sb.toString();
}
}
Saturday, September 11, 2010
Tynt programming assignment (Part 2)
mvn eclipse:eclipse
I opened the projet in eclipse. For the Junit tests I created some test input files here:
src\test\resources\TestData.txt
src\test\resources\BadInput.txt
I then created the unit test java file here:
src\test\java\com\tynt\app\AppTest.java
Here is the source for my unit test:
I created an interface I called InputReader to help me test the different assignments against the same input files.package com.tynt.app;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.io.*;
import java.util.*;
import com.tynt.app.util.*;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Test each assignment with input files
*/
public void testApp()
{
Listreaders = new ArrayList ();
Assignment1 assignment1 = new Assignment1();
Assignment2 assignment2 = new Assignment2();
Assignment3 assignment3 = new Assignment3();
Assignment4 assignment4 = new Assignment4();
Assignment5 assignment5 = new Assignment5();
readers.add(assignment1);
readers.add(assignment2);
readers.add(assignment3);
readers.add(assignment4);
readers.add(assignment5);
readerTest(readers,"TestData.txt");
try {
readerTest(readers,"BadInput.txt");
fail("Bad input should throw RuntimeException");
} catch (RuntimeException e) {
assertTrue(true);
}
}
public void readerTest(Listreaders, String resource) {
for (InputReader inputReader : readers) {
InputStream is = getClass().getClassLoader().getResourceAsStream(resource);
String result = inputReader.readFile(is);
System.out.println(result);
}
}
}
I then stubbed out the Assignment1-5 java classes which implement the InputReader interface and ran the package goal for maven using a maven eclipse plugin to fix any typos and get a baseline for beginning implementation.package com.tynt.app.util;
import java.io.*;
public interface InputReader {
public static final String INPUT_FILE = "THire_input.txt";
public static final String OUTPUT_FILE = "THire_histogram.txt";
public static final String NEW_LINE = System.getProperty("line.separator");
/**
* Reads the InputStream parameter and returns a string of the contents
*
* @param is
* InputStream to read from
* @return String of the processed contents of InputStream
*/
public String readFile(InputStream is);
}
Friday, September 10, 2010
Tynt programming assignment (Part 1)
As part of the hiring process I was given this coding assignment.
Coding Assignment #1I completed the assignment and submitted my solution but never heard from them, then the recruiter told me they went with someone else. Since I never had the opportunity to hear back from Tynt's hiring team, I decided to blog about my solution and solicit feedback on how I could do a better job.
Thank you for your interest in Tynt. As part of our recruitment process we ask candidates to complete a small programming assignment. The assignment is technically easy, but is intended to provide enough scope to allow you to demonstrate your knowledge of good programming practices. Assume that the code you are writing will reside in Tynt's main production codebase.
Development Notes
• There is no time limit to complete this exercise.
• If there are errors in the example, state your assumptions and continue.
• No user interface is required; the program will be run from the console and should
require no command line parameters to execute normally
• Assume that all files (input and output) will be found/created in the same directory as the program executes
• As part of the exercise, you may choose to write unit tests appropriate for the task.
• Use the development tools of your choice, but please write the software in Java.
• You may not use any external libraries with the exception of standard I/O and possibly a unit testing framework.
• You may not use any built-in data structures such as lists, vectors, queues etc. You
must build your solution using basic types such as integers, strings and arrays.
• You may not use any built-in sort or histogram functions.
• Please submit all available aspects of your work (source, buildfiles, executables, test
input/output etc)
• Have Fun!
====================================================================
1) Read an ascii text file named "THire_input.txt" that contains a list of numbers with integer
values, each number separated by a cr/lf
Sample input (THire_input.txt)
6
54
12
22
1
6
2) Sort the numbers in ascending order and write the results to an output file named
"THire_Ascending.txt". Format the file in the same manner as the input file (cr/lf delimiters).
Sample output (THire_Ascending.txt)
1
6
6
12
22
The assignment tied my hands by not allowing external libraries or built-in Java collections. This is done to make an otherwise simple programming assignment much more labor intensive and error prone in college CS classes. Java loses much of it's value as a programming language when you eliminate the vast libraries available. Ultimately, the code I ended up writing would not belong in an actual enterprise code base precisely because I was required to implement functionality that is provided by the language libraries. Typically you don't roll-your-own implementation of a collection unless you have a very specific need to do it, which this assignment lacks. There was no time limit to complete the exercise (a bit discouraging in that you would think Tynt would have an idea of when they needed to hire the candidate), but that didn't matter because I received five-ten nagging emails from the headhunter asking for status on my progress with it.
On to the implementation, I decided that since this was to be considered code I would put in production, Junit tests were mandatory, as well as a build script. Maven is a fantastic build tool for Java development so I created a new project using Maven as follows:
mvn archetype:create -DgroupId=com.tynt.app -DartifactId=program_assignment
This generated the structure of the project. I edited the maven pom.xml file to add a Junit dependency as well as configure the maven-pmd-plugin, which will evaluate your source and report on potential bugs or bad source formatting. Here is my final pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tynt.app</groupId>
<artifactId>program_assignment</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>program_assignment</name>
<description>FourGablesGuy's implementation of programming assignment for Tynt. Reading and parsing text files for numbers.</description>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<compilerVersion>1.5</compilerVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>pmd_check</id>
<phase>package</phase>
<goals>
<goal>pmd</goal>
</goals>
</execution>
</executions>
<configuration>
<sourceEncoding>UTF-8</sourceEncoding>
<outputEncoding>UTF-8</outputEncoding>
<targetJdk>1.5</targetJdk>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
To build/update the artifact Jar, you simply run:
mvn package
which will compile source files, run any unit tests, and package the final code.
Thursday, September 9, 2010
startSQLRepository can fail to mark ATG Content Administration projects as deployed
Maybe this will help someone dealing with issues in ATG Service 2006.3.2 or ATG Service 2007.1
Symptom:
The symptom is that a solution is reporting it is not visible in ATG SelfService.You search for the solution but cannot view it and get a message that it is not visible for the current user.
Also, if you look up the solution in dynamo administrator for the j2ee instance running SelfService, it will be missing the status property.
This is an indication that the solution is not marked as deployed in the SolutionSolutionStatus Item Descriptor of the ServiceSharedRepository.
The solution can have audience Everyone-External set, in both Knowledge and SelfService which can make the error a head scratcher.
One way to check this is by connecting to dynamo admin for SelfService and in the /atg/svc/shared/ServiceSharedRepository execute
If you do not get any rows back, then you probably have this problem, unless you just have not invalidated the caches.
Resolution:
connect to the shared schema with a database tool
update svc_soln_sstatus
set deployed = 0
where soln_id = 'soln_id' and
soln_version = version
where soln_id is the solution having the issue.
and version is the number of the version of the solution that should have been marked as deployed. To find it checked the last_modify_date and status_id columns of the rows returned from the query:
select * from svc_soln_sstatus where
soln_id = 'soln_id'
Make sure to commit the update. And clear the repository caches before rechecking.
1 the audience property is empty or only contains audiences that the current SelfService user is not a member of.
2 the solution is not marked as deployed in the ServiceSharedRepository SolutionSolutionStatus deployed = 1
Cause:
I suspect bulk importing solutions in with repository XML using startSQLRepository can leave solutions in this state where they are deployed but their status property was not set as deployed. Also messing around with ATG Service data using straight SQL on the database is a dangerous game that can burn you in countless ways.
Disclaimer
I do not accept liability for the consequences of any actions taken on the basis of the information provided by this blog.
Thursday, August 26, 2010
The two big questions
Image: Danilo Rizzuti / FreeDigitalPhotos.net
There are two questions that should be asked of each developer involved before a new software product is launched to clients:
- Are you proud of the product you created?
- Would you enjoy using it and/or recommend that your family/friends use it?
Asking yourself these two questions while developing and testing the product will change how you program and benefit the project immensely. Why? You must write good code to be proud of it. You will be motivated to do it right the first time. You will think about how your code impacts your reputation as a developer. Also, you must know how you and others would use the product to answer YES to the second question. The best written code won't help anyone if it is for a useless feature. The best written code won't matter if the whole thing becomes painfully slow to use. If their are reasons you don't enjoy the product and love it, then those should be called out sooner rather than later. Answering these questions honestly will reveal problems that testing didn't catch because nobody knows the product better than the developers. If you answer NO, then you should have some specific reasons why. Those reasons for the NO should often become the priority one (P1) issues to fix.
So often, right before a project is to release, only the testers and the managers decide if something should go live. The attitude is almost like, "Thank you Mr. Developer for your work, now we'll take it from here." A few developers will secretly cringe in horror (or internally panic) when it is decided to launch. They have been feverishly working on P1 bugs from the QA team while other severe problems in the product remain unaddressed or untested. Often QA's P1 bugs are, in the developer's opinion, the P5 bugs. Also, there sometimes is this feeling of an adversarial relationship between testing resources and developers as bugs found create more work for developers and bugs missed reflect poorly on the testers. By involving developers in the go-live decision, they are automatically held more accountible for problems in the live code, after all, it got their stamp of approval along with testing and management.
PureText
<p class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span lang="DE" ><o:p><span > </span></o:p></span></p>
You then open your Microsoft Exchange email client and paste in the text and yuck, the font has changed to comic sans at 44 point size in bright Green. You just wanted the text to paste in, but you got a lot more.
The quick and dirty solution is to open a plain text editor and paste the text there, then replace the clipboard with a ctrl+c from the plain text editor.
- Ctrl+c the formatted text
- Open notepad
- Ctrl+v, the formatting is gone
- Ctrl+a, to select all unformatted text
- Ctrl+c, replace the clipboard with unformatted text
- Alt+Tab,Tab,Tab to get the target Application window
- Ctrl+v, paste in unformatted text into the target application
Microsoft has provided a quick menu when pasting text that you can use to remove formatting, eliminating some of the annoyance but that only helps when you use their software. If you aren't able to eliminate the formatting, you could be left with having to manually re-style the pasted text, which is painfully time-consuming and frustratingly unnecessary busy work.
PureText can help out here, it essentially performs the steps to remove formatting for you each time you press ctrl+v. So to paste plain text copied from a richly formatted source with PureText installed you simple do this:
- Highlight the text to copy
- Ctrl+c, clipboard has the formatted text
- Switch to the target application
- Ctrl+v, glorious unformatted plain text is magically pasted in
A tool like this would be an excellent productivity enhancer for anyone who is authoring with browser WYSIWYG text editors like TinyMCE, and having to cut and paste between other sources. These in-browser editors are have some rich text functionality, but usually just enough to cause problems when pasting and you end up putting a lot of junk like special font settings and “Microsoft specific characters” into your application database by using ctrl+c, ctrl+v without it. This invisible styling then rears it's ugly head when you try to present the material in a browser, you get lots of square boxes in contractions or hyphenations as well as mysterious font changes as the styling interacts in unpredictable ways with the HTML page styles and CSS.
Saturday, August 21, 2010
Keeping your resume fresh
Image: Image: Tom Curtis / FreeDigitalPhotos.net
Your resume and portfolio is a marketing tool for you. Keep it fresh with your latest victories. It does not look good for a resume to only have three year old accomplishments (it's akin to a neglected castle). It is a shame when the best candidates for an opportunity are overlooked because of a stale resume and a lesser-skilled but better documented person will get the job instead. I have not been perfect at this, but I do keep a screenshot archive of web applications I was involved with. Each time a big project is completed or even when a big undertaking is conquered, I take that as a cue to update my resume with some important descriptive words about the project and what I did to help bring it home. I usually pick up a few new technologies with each project that also have helped fill out my documented developer skills.
Keeping it fresh is also a good idea because you never know when you will be asked to pack up and get out, US companies are loyal only to themselves and their shareholders and will layoff good employees at the first sign of trouble. Letting your resume go stale or failing to document your completed projects, new skills, and personal wins will impact your own professional success.
I also solicit feedback from managers and developers I work with and use the positive comments they make in my references section. I try to time my request for feedback such that I get a good positive note and the person can easily remember a specific positive thing to say about me. The manager or developer is usually are happy to do that for me, after all, I just helped them out.
You can't escape single quotes in SQL inserts with \
To escape single quote marks in DB2 SQL inserts you cannot use the backslash character. This will NOT work:
insert into LCDDB_NCD_BNFT_CTGRY_REF (BNFT_CTGRY_CD,BNFT_CTGRY_DESC,BNFT_CTGRY_EFCTV_DT,BNFT_CTGRY_TRMNTN_DT)
values (52,'Physicians\' Services','2002-8-2',null)
To insert a single quote mark in DB2 with SQL insert you have to replace single quotes with two (2) single quotes.
insert into LCDDB_NCD_BNFT_CTGRY_REF (BNFT_CTGRY_CD,BNFT_CTGRY_DESC,BNFT_CTGRY_EFCTV_DT,BNFT_CTGRY_TRMNTN_DT)
values (52,'Physicians'' Services','2002-8-2',null)
Thursday, August 5, 2010
OpenDNS Family Shield Setup guide
Access to the Internet is no longer restricted to personal computers, you can connect game systems (XBOX 360, Playstation 3, Nintendo Wii), you can connect blue ray players and watch movies transmitted over the internet, you can tether your cell phone to use your home internet and browse web sites, your iTouch can wirelessly connect to the Internet, the list goes on. Their is no 100% guaranteed way to protect all of these devices at all times from all explicit or harmful content that may exist other than turning them all off or never having them.
However, it is possible to filter out known hazards and setting up your computer with a filter takes minutes to do.
There are programs you can install on your computer like NetNanny which will protect that machine only, but you would have to find software for each device connecting to the Internet to use that method. Most modern setups for Internet access will have what is called a network router, all devices within your home, that use the same internet service, will connect to this common device. It is here at the router that the filter will be the most effective, essentially limiting and protecting all devices that may make Internet requests. I use Comcast for my Internet service and have a cheap Microsoft router for my home network.
If you only have one device in your home on the Internet OpenDNS Family Shield will also work for it and it is even less complex to setup. Go here: http://www.opendns.com/start and click sign up under the "OpenDNS Basic" option. Follow the steps to change your DNS on your router or computer. Essentially I needed to change my routers DNS settings from automatic to manual and give these two DNS server IP addresses:
- 208.67.222.222
- 208.67.220.220
If you are still following along the setup and got the successful page, you should be able to click to open the OpenDNS Dashboard. If you ran into problems getting the test page to report success, try restarting your computer first then check the test page again, if still not working try restarting the router. If still not working, try the single-computer-only setup instructions. If still having trouble, recruit a local computer savvy individual to help you.
Once successful, the openDNS success page will have a link to launch the OpenDNS Dashboard, do it! In here you need to click Settings and add your IP address as a named network, it will already be filled in and you just click "add this network" and give it the name "Home". On that same settings tab, click the link to download an important program to keep your computer protected, the link is at the bottom near the text
Keep your network's IP up-to-date with our free software.
If you use Windows Operating system, click Windows link for the Windows version of the software, if you use Mac click the Mac link. Run the program to install the IP updater software, this is critical for most Internet connections because your dynamic IP address will change periodically and OpenDNS has to associate your Internet filter preferences with your ever-changing IP address. If you have paid for a static IP address, you don't need the IP updater software.
Again on the settings tab, click the dropdown box for your networks, pick the named network called "Home" you created earlier. On the left you can pick "Web Content Filtering" and select how locked down you want the Internet, some preconfigured options are categorized as High, Med, Low. It defaults to NONE which is no better than where you started, so change it to something above NONE at least!
On the left menus, pick Stats and Logs and check the box to enable Stats and Logs and click Apply button. Now all requests from all devices connected to your router are logged! This is good because if someone tried to access explicit web sites, you will be able to see when this occurred and what site was attempted. Keep in mind sometimes sites will show up in the list that the user did not intend to access, they may have gone to espn.com and an advertiser pulled an ad from an explicit site. This ad would be blocked and show up in the log. So don't automatically ground someone for a week because of a log entry.
Hope this helps you out.
Monday, May 10, 2010
Tuesday, May 4, 2010
71st Tuesday weigh-in
Pheysey, Stephen Grant Stephen Grant Pheysey Stephen Grant Pheysey, 23,died Saturday, May 7, 2005, at his home, of alcohol poisoning. Steve was awonderful son, brother, and friend, and will be sorely missed. Steve wasborn on November 24, 1981, in Provo, Utah to James H. and Rebecca DuckettPheysey. Steve attended Cascade Elementary, Canyon View Junior High, andgraduated from Orem High School in 1999. He was awarded the Heritagescholarship to Brigham Young University and the Honors at Entrancescholarship to the University of Utah. He was currently a senior, majoringin Business Administration at the University of Utah. Steve was a brilliantyoung man with many interests and hobbies. He loved buying and fixingEuropean sports cars, going rock and ice climbing with his brothers andfriends, preparing gourmet and ethnic food for family and friends,flyfishing, bowhunting, and most outdoor activities. He loved learning andwas an avid reader. He enjoyed using his talents and knowledge to helpothers. He was preceded in death by his grandparents, Harriett Pheysey,Jack Duckett, Irene Duckett, and a younger brother, William Robert Pheysey.Steve is survived by his parents, Jim and Becky Pheysey, three brothers,Michael (April) Pheysey, David Pheysey, Matthew Pheysey, one sister, AndiePheysey, grandfather, Herbert Pheysey, and numerous aunts, uncles andcousins. Family services were held Saturday, May 14, 2005, at Berg Mortuaryin Provo. Interment was at Provo City Cemetery. Published in the DailyHerald on 5/17/2005.
Friday, March 26, 2010
69th & 70th weigh-in
70th 221.5 lb
I did a Golds Gym corporate wellness fitness test yesterday and here were my stats:
Flexibility test: 15 in (ranking: Average, 20 is Excellent)
Three minute stair step test: 84 beats per minute (ranking: Good, <81 is Excellent)
One minute push up test: 41 (ranking: Good, >45 is Excellent)
Today I ran 3.55 miles in 30 minutes, it kicked my butt.
Tuesday, March 9, 2010
68th Tuesday weigh-in
Tuesday, March 2, 2010
Coping with requirement descoping
Image: FreeDigitalPhotos.net
I am in the middle of a frantic ATG code push. The QA cycle (as usual) was a painfully short 2 days. Since the project is pretty large and was months in development, many areas of the UI were changed. Some of the changes were accepted by the QA and business team, but other changes were found to be too wonky to rollout live to thousands of agents. It was inevitable that the business side would request à la carte features from the overal design implemented to roll live (due to the short qa and hard deadline). Problems arise when removing (descoping) a rejected UI change which breaks other features because of dependencies.
I was able to deliever a rapid turnaround on descoping large functional sections of a code push. I did this by keeping a record of each file that was add/changed/removed for the project as well as correlated which business requirement(s) were the motivation behind the file's change.
Traceability saved the day.
I have not been as diciplined in the past with keeping track of changes for a project, let along keeping record of how the changes correlate to the busines requirements. Now, having done this, it is something that has helped me in the following specific ways:
- fulfill all the documented requirements of the project,
- quickly descope rejected code,
- rapidly find and fix bugs found against requirements,
- perform code reviews and explain the moving parts quickly,
- provide detailed rollout plans for the changes,
- merge in other changes into the project with ease
Not every project may be large enough to require record keeping like this. Keeping track of this stuff is boring but the benefits of doing it really make it worth the effort for me. (Just like documenting my knowledge has.)
Saturday, February 27, 2010
67th Tuesday weigh-in
Down 3 lbs. Worked out the whole week and was careful my food. A very good week for me.
Monday, February 22, 2010
66th Tuesday weigh-in
Up 1.0 and I blame the deep dish pizza at Gino's East in downtown Chicago. At least I exercised at the hotel gym while I was on the road. By the way, traveling while sick really sucks. The best food I ate in the windy city was the deep dish pizza at Gino's followed by fantastic burger at Rock Bottom. I really hated the ribs at Weber Grill or whatever that place was called... I like moist sweet ribs but these were much too dry, spicy and tough, that didn't prevent me from eating them all anyway for some reason...
Tuesday, February 9, 2010
FourGablesGuy's Best Practice tip #1478: Don't use email clients to store your knowledge
Image: FreeDigitalPhotos.net
If you were to lose all your email messages today, how high of a disaster would that be for you:
- as an employee or
- personally?
Scale where 1 is "no big deal" and 10 being "I am ruined, RUINED!!!"
If I am tempted to save an email after I have read it, I stop and think:
"Why do I want to save this? "
"Oh, it is because I will/might need this info again later."
"Well, if that is the case, it should then be put in a secure place or made into a blog post, forum post, document, etc.. on a knowledge site."
I don't always put important learned information in a blog post or in a secure archive, and sometimes I am searching my email for something that I didn't put in a place I could easily find later... However, I think the more consistently I avoid storing knowledge in my email box (either in folders, sent items, trash, etc..) the better off I will be. It takes some time up front to move knowledge to the place it belongs but it takes even more time to scour your email folders for the one bit of info out of your email-haystack when you need later. If I do have to search and find information in my email, then I always move that data into a better place, because the fact I needed the information twice indicates I will need it yet again.
In my opinion we should treat email as an ephemeral messaging tool, not as a personal knowledge compendium. So until Google Wave gets broad adoption, email is like a sticky note on your desk, neither should be used to preserve important knowledge.
Addendum: Email is a bad choice, but some do survive using it as a knowledge base tool. However, the absolute worst place to maintain important knowledge would be your IM chat history. IM chat toools are great and I use them to ask and answer questions, but I kick myself when I am looking through old chat history for a nugget of information to reuse that I neglected to preserve better. I also am frustrated when managers/coworkers repeatedly ask me questions in chat that I have answered weeks or months previously. I am trying to establish the habit to put the answers I give/receive in IM chat on a wiki or (maybe an email..) or somewhere more permanent so that I can refer back to the more stable place later. IM chat is a double-edged sword, it is fast and convenient in the short term, but you can be hurt long term by failing to capture knowledge from your chat sessions.
Awesome Personal Finance Tool
If you are looking for a tool that can help you plan and coordinate your spending, reconcile purchases so you can always pay off your card balances and always have money for the charges and checks you and your spouse make, Mvelopes is it. You can use if from any computer, Linux, Windows or Mac (you just need a browser with Adobe flash extension.) I would recommend getting coaching sessions as well to help you get the most from the tool. Mvelopes does provide free online chat support as well.
If you use the software consistently, then it will pay for itself 10 times over time.I think another similar web-based tool exists called Mint but I have never tried that one to know how it compares.
65th Tuesday weigh-in
Friday, February 5, 2010
64th Tuesday weigh-in
Thursday, January 28, 2010
63rd Tuesday weigh-in
Tuesday, January 19, 2010
62nd Tuesday weigh-in
Thursday, January 14, 2010
61st Tuesday weigh-in
Tuesday, January 5, 2010
Friday, January 1, 2010
59th Tuesday weigh-in
Up 3.0 lbs! Yeah... I wasn't very cautious with portion size this last week over the holidays and ended up bloated for my weigh-in. I did well on my exercise plan and only missed on Christmas day. Today I forgot a belt and some old jeans of mine I was wearing kept slipping down, which is a great problem to have.
About Me
blogs
Tags
- Personal (77)
- weigh-in (59)
- development (29)
- Java (23)
- loss (18)
- gain (15)
- tools (15)
- Software Engineering (13)
- Software (12)
- Austin (10)
- eclipse (7)
- J2EE (6)
- Maven (6)
- Family (4)
- XSLT (4)
- Linux (2)
- career (2)
- finance (2)
- gardening (2)
- Belts (1)
- Eleanor (1)
- IE7 (1)
- LDS (1)
- atg (1)
- car (1)
- javascript (1)
- resume (1)
- taxes Personal (1)