Finding the best target for refactoring
We are doing a lot of refactoring at the moment modifying systems to do with the PCI requirements of credit card data storage. Part of my job has been changing existing systems to comply with the requirements and we have taken advantage of this to make some tidy up some of the code base. The two ways I have been choosing my targets had been to use NDepend to find its targets using CQL (More about that in another post) and just simply looking at the number of using statements in the file.
Picking the classes with the most using statements is a useful way to find the best targets for refactoring.
Getting bitten by enums
One of the issues I have had to fix recently had me scratching my head, and promising myself be more careful when using enums in the future.
For the purposes of this example assume you have an employee class you may decide to store the gender an enum, it will restrict the choices the other developers have when creating or modifying an instance and provides intellisense. When you request an Employee object from your service layer you can then simply check the value of the enums to get the value.
In a nutshell the problem I had was that the information in the database was correct but was not setting the value of the enum. I spent a day of so working through the various layers of the application trying to find what was overwriting the value of the variable until I came to the realisation that the enum had in fact never been set.
What this led to was the system working as expected for a majority of the time and catching us out in a big way. In smaller systems this may not be an issue but when you have lots of layers in your application (too many perhaps?) its worth checking.
Creating Fake Credit Card Numbers in c#
I recently had to create a credit card number generator, nothing nefarious, just we needed unique valid credit card numbers after asking on StackOverflow and getting a less than stellar response (for the first time). I came across something on DarkCoding.Net which did exactly what I wanted but was in Java, I’ve ported it over to c# and I hope you find it useful
1: using System;
2: using System.Collections.Generic;
3: using System.Threading;
4:
5: namespace CreditCardNumberGenerator
6: {
7: public class RandomCreditCardNumberGenerator
8: {
9:
10: /*This is a port of the port of of the Javascript credit card number generator now in C#
11:
12: * by Kev Hunter http://kevhunter.wordpress.com
13: */
14: /*
15: * /**
16: * See the license below. Obviously, this is not a Javascript credit card number
17: * generator. However, The following class is a port of a Javascript credit card
18: * number generator.
19: *
20: * @author robweber
21: *
22:
23:
24: * Javascript credit card number generator Copyright (C) 2006 Graham King
25: * graham@darkcoding.net
26: *
27: * This program is free software; you can redistribute it and/or modify it
28: * under the terms of the GNU General Public License as published by the
29: * Free Software Foundation; either version 2 of the License, or (at your
30: * option) any later version.
31: *
32: * This program is distributed in the hope that it will be useful, but
33: * WITHOUT ANY WARRANTY; without even the implied warranty of
34: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
35: * Public License for more details.
36: *
37: * You should have received a copy of the GNU General Public License along
38: * with this program; if not, write to the Free Software Foundation, Inc.,
39: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
40: *
41: * www.darkcoding.net
42: */
43: public static String[] AMEX_PREFIX_LIST = new[] {"34", "37"};
44:
45: public static String[] DINERS_PREFIX_LIST = new[]
46: {
47: "300",
48: "301", "302", "303", "36", "38"
49: };
50:
51: public static String[] DISCOVER_PREFIX_LIST = new[] {"6011"};
52:
53: public static String[] ENROUTE_PREFIX_LIST = new[]
54: {
55: "2014",
56: "2149"
57: };
58:
59: public static String[] JCB_15_PREFIX_LIST = new[]
60: {
61: "2100",
62: "1800"
63: };
64:
65: public static String[] JCB_16_PREFIX_LIST = new[]
66: {
67: "3088",
68: "3096", "3112", "3158", "3337", "3528"
69: };
70:
71: public static String[] MASTERCARD_PREFIX_LIST = new[]
72: {
73: "51",
74: "52", "53", "54", "55"
75: };
76:
77: public static String[] VISA_PREFIX_LIST = new[]
78: {
79: "4539",
80: "4556", "4916", "4532", "4929", "40240071", "4485", "4716", "4"
81: };
82:
83: public static String[] VOYAGER_PREFIX_LIST = new[] {"8699"};
84:
85: private static String ReverseString(String str)
86: {
87: if (str == null)
88: return "";
89: var revstr = "";
90: for (var i = str.Length - 1; i >= 0; i--)
91: {
92: revstr += str[i];
93: }
94: return revstr;
95: }
96:
97: /*
98: * 'prefix' is the start of the CC number as a string, any number of digits.
99: * 'length' is the length of the CC number to generate. Typically 13 or 16
100: */
101:
102: private static String CompletedNumber(String prefix, int length)
103: {
104: String ccnumber = prefix;
105: // generate digits
106: while (ccnumber.Length < (length - 1))
107: {
108: double rnd = (new Random().NextDouble()*1.0f - 0f);
109: ccnumber += Math.Floor(rnd*10);
110: //sleep so we get a different seed
111: Thread.Sleep(20);
112: }
113: // reverse number and convert to int
114: String reversedCCnumberString = ReverseString(ccnumber);
115: var reversedCCnumberList = new List<int>();
116: for (int i = 0; i < reversedCCnumberString.Length; i++)
117: {
118: reversedCCnumberList.Add(Convert.ToInt32(reversedCCnumberString[i].ToString()));
119: }
120: // calculate sum
121: int sum = 0;
122: int pos = 0;
123: int[] reversedCCnumber = reversedCCnumberList
124: .ToArray();
125: while (pos < length - 1)
126: {
127: int odd = reversedCCnumber[pos]*2;
128: if (odd > 9)
129: {
130: odd -= 9;
131: }
132: sum += odd;
133: if (pos != (length - 2))
134: {
135: sum += reversedCCnumber[pos + 1];
136: }
137: pos += 2;
138: }
139: // calculate check digit
140: int checkdigit =
141: Convert.ToInt32((Math.Floor((decimal) sum/10) + 1)*10 - sum)%10;
142: ccnumber += checkdigit;
143: return ccnumber;
144: }
145:
146: public static String[] credit_card_number(String[] prefixList, int length,
147: int howMany)
148: {
149: var result = new Stack<String>();
150: for (int i = 0; i < howMany; i++)
151: {
152: int next = new Random().Next(0, prefixList.Length - 1);
153: String ccnumber = prefixList[next - 1];
154: result.Push(CompletedNumber(ccnumber, length));
155: }
156: return result.ToArray();
157: }
158:
159: public static String[] generateMasterCardNumbers(int howMany)
160: {
161: return credit_card_number(MASTERCARD_PREFIX_LIST, 16, howMany);
162: }
163:
164: public static String generateMasterCardNumber()
165: {
166: return credit_card_number(MASTERCARD_PREFIX_LIST, 16, 1)[0];
167: }
168:
169: public static string Reverse(string str)
170: {
171: // convert the string to char array
172: char[] charArray = str.ToCharArray();
173: int len = str.Length - 1;
174: /*
175: now this for is a bit unconventional at first glance because there
176: are 2 variables that we're changing values of: i++ and len--.
177: the order of them is irrelevant. so basicaly we're going with i from
178: start to end of the array. with len we're shortening the array by one
179: each time. this is probably understandable.
180: */
181: for (int i = 0; i < len; i++, len--)
182: {
183: /*
184: now this is the tricky part people that should know about it don't.
185: look at the table below to see what's going on exactly here.
186: */
187: charArray[i] ^= charArray[len];
188: charArray[len] ^= charArray[i];
189: charArray[i] ^= charArray[len];
190: }
191: return new string(charArray);
192: }
193:
194: public static bool isValidCreditCardNumber(String creditCardNumber)
195: {
196: bool isValid = false;
197: try
198: {
199: String reversedNumber = Reverse(creditCardNumber);
200: int mod10Count = 0;
201: for (int i = 0; i < reversedNumber.Length; i++)
202: {
203: int augend = Convert.ToInt32(reversedNumber[i]);
204: if (((i + 1)%2) == 0)
205: {
206: String productString = (augend*2).ToString();
207: augend = 0;
208: for (int j = 0; j < productString.Length; j++)
209: {
210: augend += Convert.ToInt32(productString[j]);
211: }
212: }
213: mod10Count += augend;
214: }
215: if ((mod10Count%10) == 0)
216: {
217: isValid = true;
218: }
219: }
220: catch
221: {
222: }
223: return isValid;
224: }
225: }
226: }
The Joys Of Interviews
In last couple of weeks we have been interviewing new contractor candidates. The standard has been pretty good with a few notable exceptions;
- If you say you find multi-threading easy yet do not know what the lock statement does I tend not to believe you are any good at it.
- If you have six years experience in c# and describe your competence as excellent, you really should know the difference between abstract and sealed.
People who need to revise for a simple OO test make me shudder.
Hiring again
We’re hiring again at work, getting some contractors in to help us with the deliverables in the next three to six months. From the last time we were interviewing the standard seems to be significantly higher, which I imagine is due to not as many companies taking on contractors. I have heard about people despairing over the standard of .Net developers but I have noticed that many more seem to have an understanding of mocking, testing and the SOLID principles than even a year ago.
So many CV’s came in we changed our hiring process and asked sent the applicants a single method to improve maintainability and email us the results, the standard was pretty high (although the original code was really bad) but I think it will give us a good starting point to discuss with the candidates we get in for interview.
As someone involved in the hiring process we can now afford to be more selective, I have found with our current hiring process we have a reasonably simple multiple choice OO which as perhaps a little too much trivia and a very simple practical which I don’t think that this is enough to really understand how good the candidate is, I would rather that they thought more rationally about design and maintainability than knew their way around SqlCommand and the SqlDataReader.
For any candidate we interview, they should understand unit testing, IOC, separation of concerns, know why large classes and methods are wrong and expect to write code in the interview, not being able to write code under pressure is not a reasonable response. We won’t give them FizzBuzz but might ask them to solve a problem on the whiteboard.
Lastly, if I am interviewing you, one last piece of advice, don’t suggest that I use DataSet’s in my Domain Objects we have enough of that sort of architecture here already!
What’s your interview process and has it changed over the last couple of years?
Can you still be a single platform developer?
When I joined my current company two years ago, I joined specifically as a Winforms developer. At that time the company had seperate Winforms, Web and Service teams within the development department. Within a year this had changed into one cross functional team working on various projects, so I am now exposed to more web programming (ASP.NET 2.0/3.5) than I expected.
This is definitely a good thing and although I have struggled with some of the challenges of working with a stateless model I am getting to grips with writing the code and getting my ideas out there. I feel a more rounded developer and a more useful team member.
But I was thinking today about if people are still ‘web only’ or ‘winforms’ only developers I think even as little as two years ago that may have been the case. Now I am not sure that you can afford to be. Or if you are, you’re much better off on the web side of the fence. That said, I can never imagine telling a current or prospective employer that I would not be willing to work on a technology even in good times.
I suspect the answer is, and this is from no scientific reasoning and a few Stella’s, that while you still can be a single platform developer, you probably shouldn’t be. The Pragmatic Programmer tells us to learn a new language every year, with the amount of new technology that comes from Microsoft every year perhaps you may just need to learn a new platform.
definitely
Listen to your onsite customer
Recently we have been rolling out a project at work which has been in the planning stages and worked on for about 6-8 months off and on. Once the main development had started we made sure that we had regular updates with the main stakeholder. This involved a meeting once a week to show our progress discuss what they liked and didn’t like and which changes they would like to make.
The project is now ready for deployment and we are meeting a lot of resistance from the business. Our main customer seemed pleased with the product and was happy as the iterations when by, however the actual end users seem much less pleased.
I heard recently that if you don’t succeed, make sure you learn from your failure, I assume that some sort of middle ground will eventually be found and that the project will be delivered, but there are a couple of things that I will be taking away from this project.
- Make sure that the drops of your code are seen by as many people as possible, especially the people who will be working with the project every day
- Early design and mock-ups to let customers know the planned UI are very useful, I have heard good things about Balsamiq for putting together mock designs quickly
- Make sure you are prepared to listen to what the customer wants from the very start, rather than letting the design be dictated by the technology
Much of the work I do is with services and apps without a UI so I don’t need to worry about the human interaction, the next time I do I will be ensuring that I and my team will not be making the same mistakes again