Subj : Re: programming job market in bay area in US To : comp.programming From : rem642b Date : Fri Jul 29 2005 05:53 am > From: Christer Ericson > I made no remark about the production of bugridden software; I > commented on the issue of a single programmer generating lots of bugs > and slowing others down. Let me see if I can explain my understanding in a way that you'll agree is the same as you originally intended: This one programmer doesn't bother to unit test any of his code. He just writes a shitload of code, glances at it and thinks it'll work, and then submits it *UNTESTED* to others for approval. Others then need to read his almost totally absent comments just to figure out what problem he was trying to solve, before they can know what test data to feed to it. When they finally figure that out, then discover his code doesn't work. So they have to try to figure out what's wrong with it. By the time they fix it, they have spent more time testing and fixing his code than it would have taken them to do the whole bunch of work themselves. Let me know if we're "on the same wavelength". With me, you wouldn't have to worry about that. I unit test all my code, most of it at the single-line level, occasionally in cases where I've written similar code many times calling the same tools many times, so I know for sure how each line of code will work without testing it, I'll write a whole block of 2-4 lines of code at once and then unit test the whole group as a single unit. For example, I might write this code so easily: (let ((sorlis (sort (copy-list nums) #'<))) (mapcar #'- (cdr sorlis) sorlis)) and then test it like this: * (setq nums (list 9 3 5 7 6 1 0 8)) ;Then above code: (1 2 2 1 1 1 1) ;The purpose of the code was to detect how close I was getting to ;exhausting all the integers within some interval. Because two 2's show ;up adjacently I know there are two missing integers separated by one ;present integer. ;Yes, I actually wrote that code right here while composing this ;message, then started up CMUCL to test it, and it worked right the ;first time. I put a comment at the top of each function saying what it does, what args are supposed to be, anything else that must be set up before the function can be called, what decisions it makes, what return value(s) it gives under what circumstances. For example (from actual code): ;Given number N, initialize process of finding factors that make it not prime. ;Note: For large N, this is a bad way to do things, choosing N then trying ; to find its factors. If you want to know both the factors and their ; product N, it's better is to directly synthesize the factors, then just ; multiply them to get N, much faster, much much much faster for large N. ;However for small N this is fast enough, even if N is prime so no factors ; will be found, as a simple proof it's really prime. ;** Warning: This will extend g*primes as needed to include all primes ; to square root of N. ;Return value is list (numberToFactor sqrt(num) enumerationOfPrimes) (defun n-gpsq-start-find-factors (nc) ...) ;Brute force, given n-gpsq-start-find-factors already called to set up the ; number and the continuation-process, find next factor of that number, ; or give up if it's prime. Do **not** call this for large numbers, ; because this will just run forever trying to reach sqrt(n). ;Note that as soon as a factor is found, that factor will be divided out ; from the continuation, so don't let that confuse you! For example, if ; the number is itself a prime, after reaching square root that number ; itself will be divided out leaving behind the number 1. ;Primary uses for this: (1) test small p to see if prime (call just ; once), (2) factor small n completely (call until enfac shows just 1). (defun next-find-factors-gpsq (enfac) ...) My unit tests per line of code consist of setting up test data for the parameters to the function I'm constructing, then writing the first line of code and executing it and verifying the result looks good, then writing the second line of code and executing it and verifying the result looks good, etc. until the last line of code is tested and the return value is correct and ready to return. Then I finish the framework for the function definition, run it to actually define the function, then I copy the header for the function and the assignments of test values to parameters to the bottom of the function, delete all the cruft, to yield a valid function call form. For example, if I was line-by-line testing like this: (defun next-find-factors-gpsq (enfac) ;(setq enfac (n-gpsq-start-find-factors 25)) then my unit test for the whole function just once would be: ;(next-find-factors-gpsq (n-gpsq-start-find-factors 25)) and my unit-test for the whole function as many times as wanted would be: ;(setq g*enfac (n-gpsq-start-find-factors 25)) ;Do once for setup ;(next-find-factors-gpsq g*enfac) ;Repeat until g*enfac = (1 ...) If the function is complicated enough that I want to test boundary cases, then I set up several such unit-function-test rigs, for example in that case I might want to be sure it works correctly if N is 1 or 2 or 3 or 4 (trivial cases) or 500 (forces g*primes to grow to meet sqrt(500)), in addition to the normal-sized case of 25 that I tested first. So anyway, when I'm done I have functions that are fully documented by both explanatory comments and test cases that are known to work. > (Incidentally, attention to detail is a quality I value highly in > programmers!) Then you should appreciate my attention to detail! A lot of the javadoc on the API WebSite has glaring mistakes that I've spotted, such as the URL encode/decode where somebody copied the algorithm description from one (where it was correct) to the other (where it says the opposite of what actually happens) and didn't bother to edit it to read the correct direction for the latter (except they did get the + <-> space reversed correctly). For encoding, yes you check the character, if it's alphanumeric etc. you copy it as-is but if it's something else you encode as hexadecimal, but when decoding anything except + you don't look at the input character at all except to see whether it's the hexadecimal-code prefix or not, where in the former case you gobble several characters to complete the hexadecimal value then write out just one (1) decoded character. http://java.sun.com/j2se/1.3/docs/api/java/net/URLEncoder.html (correct) http://java.sun.com/j2se/1.3/docs/api/java/net/URLDecoder.html (wrong) > I do care a lot about the (non-)production of bugridden > software. However, bugridden software is different from > bugridden code (which, weirdly, is something Philip is > completely unable to understand). Um, I know if there's bug-ridden code, then it causes the overall software to have bugs or crashes or whatever. If the code is perfect, but the design is flawed, then the overall software again will not work correctly. But if both design and code is perfect, that would seem to make the program work correctly, assuming the machine (computer) itself is working properly. Then the user can screw it up, but if documentation is good and training is good and online help is good and UI is natural enough then the user doesn't make enough mistakes to destroy all that work making a fine program. Did I overlook anything? > Specifically, the reason I don't worry much about the number > of bugs caused by a given programmer ... Are you saying you wouldn't appreciate that fact that my code is all unit-tested before you see it, whereas that other guy's code is crap he threw together and didn't test? So you'd just as soon have his cruddy code as my fine code? I'm not sure I understand you fully. (Eliza 1969) > Code bugs, when they occur, typically do not slow anyone down > in that new features are fairly well-tested before a team > release. But what about the difference between my team, where my code is already working before it's fitted with the other code, so it takes only two days to get a new release out, compared to that other guy's team, where his code takes a week for the other team members to figure out what he's trying to do and another week to fix it, before they can go back to square one to try fitting his code with their code again which takes another week because they're so exhausted from those first two weeks? > In a programmer interview, rather than being concerned about > a programmer's bug counts, I'm instead concerned about issues > such as: overall knowledge, problem solving skills, need of > supervision, productivity and self-motivation, people skills, > etc. I know how to brainstorm use cases until they are precise enough that implementing them won't be a big mistake, and how to solve programming puzzles providing that the basic tools are already known to work, and how to ferret out which basic tools are of questionable use so that we really need to check them out before committing to a timeline for the project, and how to quickly check them out and come to a decision whether there was a problem or not, and in some cases how to hack around a problem by adapting some other tool instead of the one that just doesn't work as advertised or as expected. I don't need any supervision, but I need feedback whether I understand the goal correctly so I won't be implementing something different from what is desired, and I would really like feedback on how you're coming with integrating my yesterday's code module with the rest of the project, and I'd like to know when it's integrated so I can play with the overall program and see if it'd using my code the way I thought it would. > Many of these issues we can fairly accurately assess during the > interview, ... But how do you decide whom to interview in the first place? For example, how come you haven't interviewed me in the past ten years? Is it because you never had any money to hire anyone all that time, or you never had any programming jobs except for very specialized environments (Oracle, Sybase, JBoss, MS-Windows device drivers) where I didn't have the very specific experience and knowledge you absolutely needed for the very specialized job, or you would have hired me except your recruiter was scanning resumes for particular buzzwords and I happened to use different buzzwords for exactly the same skill so your recruiter overlooked my resume, or you can't process any resumes except in MicroSoft Word, and my resume is in plain ASCII so you couldn't even see it on your system? .