Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Tuesday, May 4, 2021

CD-ROM Express from PC-Kwik

CD-ROM Express from PC-Kwik

The final product released by my old employer, PC-Kwik in 1996.


So, I was browsing around a few weeks ago for the PC-Kwik logo for some reason, I don't quite recall now and saw someone on eBay selling an old copy of CD-ROM Express for just a couple of bucks, and a bit more shipping.  I thought it was worth it for the nostalgia...

I worked at PC-Kwik from September 1993 till we shut our doors on December 31, 1996 (though I'll admit that last day I jetted around 3pm rather than stick it out all the way till the end of the business day at 5pm).

While I wasn't one of the main developers of the CD-ROM Express utility, I did write the MS-DOS based install program for the DOS/Windows 3.1 version of it (but not the Windows 95 version).  And I was the main QA tester for both versions, and I was the editor of the user manual.  

I also helped with the design of the box.  Initially the designers made it so there was a complete image of a CD within the Mercury helmet, but I thought it looked bad, like someone took a car cigarette lighter to a plastic helmet, and suggested resizing it, cutting off the bottom so that the curve aligned with the curve of the helmet, the way it is above.  I think it looks much better this way.



Unfortunately CD-ROM Express failed as a product.  There were several reasons, including bad timing, we released it just as consumer level CD-ROM drives themselves got fast enough to obviate the usefulness of CD-ROM Express.  

While skillful, and maybe lucky, marketing could've gotten around that, this just wasn't the product our customers wanted to buy from us.  Doing technical support I talked to PC-Kwik customers every day, and they made it clear what they wanted us to make was Super PC-Kwik, our fast hard drive caching utility, and our PowerPak programs, for Windows 95.  If we could've converted those from DOS to Windows 95, they would've bought them.

But alas, we didn't listen to them...

Thursday, February 28, 2013

Code Complete - Target Audience For Code


Twice today I read quotes or paraphrases of a statement from the book Code Complete by Steve McConnell, "Write Programs for People First, Computers Second".

I certainly understand that, I've been doing maintenance programming for the past 20 years, so I know what it means to be the human/programmer audience for code.  I know how hard it is to read bad code and how hard it is.  I'm also fully aware that a lot of code that is hard for people to read is often buggy so though the computer understands it, the computer doesn't end up doing what the people would prefer it was doing.

And I know what it's like to work with a guy who refuses to write easy-to-read code angrily telling anyone who gives him feedback, "I don't care! If someone is too stupid to understand this, then that's not my problem!"

It's not that I don't know what it means…

However, thinking about the statement itself…

If the computer isn't your first target "audience" for the code you write, why are you writing it?  You might as well not write code if it isn't primarily for the computer to execute.

That database code?  If the computer is only your second choice as a target, how about hiring some file clerks and giving them the instructions?

That graphics program you're writing, if the computer isn't your main audience, how about going and buying some top quality pencils, brushes and paints and go out in the fresh air instead of sitting on your butt in front of the computer?

So, really, if the computer isn't your primary target, you should write the code at all.

That said, of course, once you're committing to writing code to solve the problem, by all means write it so the next poor schmuck can read it and understand it (bearing in mind, that next poor schmuck might very well be you in a short while…)

Tuesday, April 10, 2012

I Haven't Been Trained On That (or a mild work rant...)

For years at a previous job, where over time I'd written a lot of code for a number of modules of our software, including creating whole modules by myself, one of my favorite jokes was when someone would come to my desk to ask me how a particular part of the software worked, especially if I knew the querent knew I wrote that part, I'd answer "don't ask me, I haven't gotten training on it yet."

I was just trying to be a little funny, and even if I said it with a straight face, I still didn't let them leave my desk without giving an answer to their actual question.  Whether it was funny or not is not my current point...

Unfortunately at my current job, that is the actual answer I get to a lot of my queries of other developers who've been working on the software far longer than I have.  The developers who wrote parts of the software tell me things like "I know I wrote it, but I don't remember how it works, you'll have to figure it out on your own."

For the last few months I've had one task on my plate that has me sort of whipped...  But I can't get any instructions on how to set up the test data to duplicate the problem so I can come up with a solution.  The answer I get from the developers who've worked on it is "talk to So-and-So" and when I talk to that person, "I don't remember, read the source code."

And it's not like I remember every detail about all the code I've written, and when people have asked me questions about my code, I haven't always been able to give an immediate answer.  I've resorted to "let me review and do a little research, and I'll get back to," but currently I don't really get that, I just get a "I don't know, you're on your own," sort of answer.

Wednesday, April 13, 2011

What is computer programming?

Recently on Slashdot I read a comment about a new Microsoft programming environment, TouchStudio, for the Windows Phone 7 that allows programmers to write programs on the phone to run on the phone.  Another commenter wrote:

So, it appears to be not true programming but just script manipulation.

Well, that brought up something that I've heard a lot, especially as a professional FileMaker Pro application developer...  What is programming?

Other developers working in FileMaker Pro used to say that it wasn't programming, but just "scripting" or things (often with some concerns over how it would look on their resume and what negative effect it would have on future career options).  Sure, with FileMaker Pro we didn't sit down with a text editor and write code to compile or interpret, it had a lot of point -n- click, choose items from a list, etc. to create a script.  And FileMaker Pro used the term "script" for code written in it.

But I don't agree that it isn't programming.

To me, computer programming is simply about instructing the computer what to do later.

Later is any time after the instructions are created, whether it's a one-time fix for something, or a piece of code that'll run a thousand times a second for a few years or an event handler to deal with users clicking an OK button somewhere or a scheduled task for every day at 3pm.

The way I see it, whether it's assembly language, BASIC with line numbers,  C, Java, SQL, JavaScript, FileMaker Pro, LabVIEW, Access, Python, Ruby, Logo and a virtually unlimited list of others (and I could grudgingly add VisualBasic...) if you're using it to tell the computer what to do sometime after you've given the instructions, it's computer programming...

Blessed be those who speak to inanimate objects...
...For they shall be computer programmers.

From a sign on my uncle's old office in the math department of Whittier College in 70's...

Thursday, January 6, 2011

MTA Apps are Whiz Kid Certified

Lately the subway trains have had ads posted on them by the Metropolitan Transit Authority, who runs them, about the various improvements they're making to New York City's transit system.  As one says "a city is only as good as its transit system."

One of them admits that they didn't create their own apps, "Our apps are whiz kid certified.  Instead of developing transit apps ourselves, we gave our info to the people who do it best."


Now, as what they would probably qualify as a "whiz kid" I don't think I'd certify the app based on the screen shot they show.  From a UI perspective it looks awful.

A quick glance at it and I'm confused.  Those are definitely subway lines, but if I was looking for one, they don't seem to be in any order.  The rectangle in the upper left makes sense, 1 2 3 and 4 5 6 on the next line.  But why is J between 3 and 7?  That makes no sense!

My first thought was maybe they were ordered by their routes, although that might make sense for someone who really knows the whole system, knows that 2 3 4 & 5 all run pretty near each other for long distances.  But if that was the case, why isn't J by Z?  J and Z run perfectly parallel their whole routes and are so tied together a famous singer even used the J & Z lines as his stage name...

Or maybe I should make an allowance for half the screen being cut off from the ad?

Hopefully it's not made by the same people who wrote the software that creates their status alerts on their home page.  During last week's blizzard one had this:

MTA Service Notice
Due to ongoing snow related conditions:
There is no Description: http://www.mta.info/status/widgetImages/nyct/Q.giftrain service between the Astoria-Ditmars Boulevard Station and the Coney Island-Stillwell Avenue Station in both directions.   
There is no Description: http://www.mta.info/status/widgetImages/nyct/N.giftrain service between the Coney Island-Stillwell Avenue Station and the Whitehall Street Station in both directions.
Please allow for additional travel time.


Ok, sounds reasonable.  One of my coworkers, who very, very rarely takes the subway, went to the Q station nearest her and found out it was closed.  She thought it was running.

I did, too.  Until I looked at a route map.  Turns out Astoria-Ditmars and Coney Island are opposite ends of the lines.  Basically, that Q notice translates to "there is no Q service" because it's not running from the stations at each end of the line.

My guess is the MTA must have some application which lists the lines and they just check the first and last stations that are out of service and it generates the message for their web page.  But it doesn't recognize that if the first and last stations on a line are checked, then the whole line is out of service.

Wednesday, May 26, 2010

Snatching Defeat from the Jaws of Victory

After all the work I put in to the recruitment stuff from Cyrus Innovation for a senior Java / Ruby developer job, I lost it.

A few weeks ago I had a really good interview with their technical recruiter, Glenn. Then he gave me a code test to do. He mentioned the Ruby one, but then corrected himself and gave me the URL to the Java one. Since I mentioned I like learning new things, I dug around and fiddled with the URL for the test to find the Ruby one and did both of them, with an email explaining it was my first ever Ruby code (it was). A while after sending them to him I got a response:
I just heard from our development team, and this is one of the best code tests we've seen at Cyrus! The Java submission was, by our standards, essentially perfect, and the Ruby test was also extremely strong.

So, it looked good. I spent some time on the weekend putting together the job application document, getting it printed and signed and scanned back in.

Then Glenn arranged for me to do a pair programming type session with Alfredo on Monday for a few hours. We used Skype and its desktop sharing and voice. It wouldn't let us do both desktop sharing and video, however. That session went okay, not fantastic, but not yet a disaster and afterwards Glenn gave me positive feedback.

For Tuesday night he arranged an even longer session for me with Matt there. I felt that went even better for the two of us. And Matt sounded really positive when we got off the Skype thing.

In both sessions we did some refactoring of the code I wrote for the initial Java test and added a little new functionality. I guess I should've guessed, since in neither session did we ever finish the functionality we were adding. A lot of discussion about how to do it and in both cases we began with test cases and some refactoring to move out what looked like would be good interfaces, but never quite completed.

It was fun both times working with Alfredo and Matt. We laughed, swapped some stories about coding and platforms and weird things in tools and all that. I described some of how my project structures things and what-not. Both guys were pretty cool to work with.

A little while later I got an email from Glenn:
I just had a chance to sit down with Matt and talk about the second pairing session. As I've heard from everyone thus far, it was a real pleasure working with you, and in terms of personality, everyone here agrees that you would be a great fit at Cyrus and would get along well with the team. Matt and Alf both spoke highly of your instinct toward agile practices, and your deep knowledge of design patterns.

There were a couple of points of concern that came up in both of the pairing sessions over the past two days. Matt mentioned today that parts of your code test seemed like they were packed a bit too tightly to pull things out easily - a fact that was made apparent when adding a new parser to the project, and that your approach to refactoring the code could have been better. Alf noted yesterday that the flow between testing first, coding, and then following up with additional tests was not as smooth as it could have been. Because we'd be bringing you in at a senior level here at Cyrus, these became points of concern for the development team, and unfortunately we have decided that because of this, we have to pass at this time.

I think remote pairing is certainly a challenging prospect, and as discussed, it is largely uncharted territory for Cyrus. To that end, in the event that you relocate or travel to the NY area, I would love for you to come in and pick up the recruiting process again. We would could conduct a pairing session in person to ensure that any potential issues related to the remote connection are not to blame for the team's assessment.

It has been a real pleasure speaking with you, and the team wants to thank you for taking the time to go through our recruiting process. I wish you all the best, and please keep in touch.
So that's sort of that... I feel like I put in an awful lot of effort on this one.

I suppose part of the problem was me. When it comes to the job hunt, I do manage to mess things up that would normally be easy. If one of my teammates asked me to do the same things with the code that Alfredo and Matt did, I'd probably jump up to the board, or a notebook and start scribbling just what to do and get it done quickly. But when I'm being tested for a job interview I'm nervous and I screw up easy things. I don't handle that context very well.

Another problem is I'm sure I wasn't at my best in the evenings after full work days. Caffeine probably wasn't a good substitute for being well rested and fresh.

Maybe I also let the friendly chit-chat get away from us. Not that we shouldn't have been friendly, but discipline... Maybe I should've tried to focus a little more on the tasks at hand and solving the problems put to me. Then again, that gets harder to do after a full work day as well.

The remote stuff added to the difficulty. It's not trivially easy to pair that way even with teammates I've known for a few years and worked in-person with, so with someone I don't know, I think communication that way was a little tougher and maybe we didn't pass information back and forth very well. Without video we couldn't even use our hands for body language while talking.

So, at this point, now that I have a better idea of where they're going with the code, and given how much time and effort I've put in already, it's probably worth it to spend a few hours this weekend updating the test code I sent them and just emailing it to Glenn with "here, I've done some of what Alfredo and Matt had me doing..." and see.

Not much to lose, and lots to gain if I'm successful.

Monday, May 10, 2010

Job Hunt and a Coding Test in Java and Ruby

Thursday evening last week I had a Skype interview with the technical recruiter from a small New York City company, Cyrus Innovation.

One of the things we talked about was if I was interested in sticking with Java or if I'd be flexible about other technology, Ruby, in particular. I said I was open to other technology, but mainly focusing on Java because as it's what I'm doing day-to-day, it's what I'm most comfortable interviewing about.

At the end he said he would send me the Ruby coding test. I said something like "sure, I'll try that. Doing it in Ruby should give me a push to learn a little more Ruby". Then he apologized and said it was a slip of the tongue and he would send me the Java test.

Shortly after that I got an email from him with a link to their Java based coding test on their website. I read through it, and since he'd mentioned a Ruby test, thought I'd just tack on "_ruby" to the URL. That worked and I got a Ruby version...

So, Friday night I began work on the Java one, wrapped it up on Saturday evening and then decided to try it out in Ruby. It was essentially the same test, although the text on the website was formatted a little different and it gave the individual input files and output files instead of a zip containing them all, but really, the same test.

I worked from late Saturday night till nearly dawn on Sunday, searching Google for some Ruby help and digging in the index of The Ruby Programming Language by Flanagan & Matsumoto to find answers to my questions about getting it done in Ruby. I actually had a lot of fun doing that. With a dearth of ideas for what to program, rather than a lack of interest in learning, this gave me a specific project to do.

I continued it later Sunday morning and by early evening had the same output from the Ruby code as I did the Java code, and the same unit tests. I didn't copy and translate the code directly, I tried to use Ruby idioms where I understood them, but since it was my first real Ruby code, I doubt it's top quality.

I emailed both zip files to Cyrus Innovation with the explanation that he gave me the Java test and mentioned the Ruby one, so after finding I did it just so I could learn a little more Ruby. Hopefully that'll make some kind of good impression and back up what I said about being interested in learning (which is certainly true!).

So that's step 2 of 4 from their recruitment process done. Everything he told me about the company made it sound like a place I'd enjoy working. At this point I really want to get through the next steps and I hope they hire me, it sounds fantastic.

The only problem is step 4 of the process... I can't easily fly there to spend a day in their office and fly back. He said he'd talk to some people there about what might be done via the internet for that.

To Mock or not to Mock, that is the question...

Yoda: … But beware the mock side… Easy they flow, quick to join you in a test. If once you start down the mock path, forever will it dominate your destiny, consume you it will...
Luke: … Is the mock side stronger?
Yoda: No, no, no. Quicker, easier, more seductive.
Luke: But how am I to know the good mocks from the bad?
Yoda: You will know…

Over the last three years that I've been on a project doing extensive unit testing (not that I was ever doing unit testing before, though I'd heard the name) one of the major battles our team has had is about using mocks. Primarily it's "do you mock concrete classes or not". Mocking interfaces isn't such a question because that's the whole point of an interface, you write whatever implementation you want, and in a unit test that could very well be a mock object.

Mocking collaborators is a great way to work out the interactions between objects, and for stateless service methods allows you to isolate your tests to primarily just the object you're trying to test without by not forcing you to set up way too much data and classes and state around the other objects.

And of course, you have to think about the purpose of testing. Some say it's about using tests to design your objects. I don't disagree, but based on pretty long experience writing software, I think another purpose of tests is to "protect" your code from future changes.

We all know that code changes as the product/project or whatever evolves and goes through future changes, that's pretty much a given. Having spent years working on untested code, I like the idea that tests tell you later when changes affect code by failing. They tell you that a future change, possible to some other class, requires you to change a class you may not have thought of. It's great, and it helps reduce regression bugs later on.

At first it wasn't a question, we used JMock version 1 and that only allowed mocking interfaces. Using it we had test code that looked like:
Mock mockService = new Mock(BlahBlahBlahService.class);
mock.expects(once()).method("doSomething").with(eq(domainObjectId), eq(newValueAmount));

And so forth. It works, but the part that's inelegant is having the method name in quotes so that refactors don't automatically change it and you can't easily find where that method is called.

But then with JMock2, we got better syntax like:
BlahBlahBlahService mockService = createMock(BlahBlahBlahService.class);
addExpectations(new Expectations() { {
one(mockService).doSomething(domainObjectId, newValueAmount);
} });

But with this JMock2 also brought the ability to mock concrete classes... And that's where I think the trouble begins.

On our project we've set up "builders" for just about every domain object so that in tests we can fairly easily create a stateful domain object with any state our tests need. It works quite slick in our test code:
DomainObject domainObject = new DomainObjectBuilder()
.someStringValue("xyz")
.someOtherStringValue("abc")
.someObjectValue(new Object())
.someIntegerValue(123)
.build();

Granted, some can get fairly complicated with a test requiring building multiple objects. I'm not saying it's always 100% easy. And often if setting up data for your unit test is really hard, it's a sign your design isn't quite right and it's time to think about changing that. On the other hand, I kind of think that if the code is complicated, the test should be equally so, they go hand in hand, and if the test is too much simpler, it may not be a good test.

When we switched to JMock2, a lot of the younger, less experienced guys, who didn't have much experience at maintaining older code through generations of changes wanted to start mocking every object except the one being tested. They were concerned about "purity" and that every unit test had to be a "pure unit test" which meant that the object being tested was the only one not a mock. They wanted all other objects mocked so that each test tested only one single object.

I understand the argument about purity, but I disagree, if they're too pure, they're not future-proofing your code (in metallurgy, pure steel isn't as flexible if impurities, such as manganese aren't added). By mocking everything else, it prevents our tests from catching necessary changes in an object if the objects it collaborates with change in some way. The test is essentially "putting words in the mouth" of other objects. I think if an object is dependent upon another object, it's good for the test to be equally dependent.

Another coworker gave a good argument against "purity". How would you test this function?

public String truncateTo10Chars(String source) {
if (source.length() > 12) {
return source.substring(1, 12);
} else {
return source;
}
}

A mock test for that would be simply silly, mocking a String? It would look like:

String mockString = createMock(String.class);
String truncatedString = "123456789012";

addExpectations(new Expectations() { {
one(mockString).length()
will(returnValue(15));
one(mockString).substring(with(equalTo(1)), with(equalTo(12)));
will(returnValue(truncatedString));
} });

String actualString = truncateTo10Chars(mockString);
assertThat(actualString, is(truncatedString));

That'd be a bit of a crazy test...

One of the unit tests that a mock fan wrote in our code dealt with a domain object's method returning a particular enum value. The mock fans didn't want to build it, they wanted the test to be pure and the test of the class calling the domain object to mock the domain object to avoid "testing" the domain object itself. I tried to suggest "well, what if in the future it returns a different one of the enum's values, we'll have to change the code calling it because it's dependent upon what's returned, but the test won't tell us because it's still the same data type and it won't fail."

I lost the argument, not by logic but by not talking loud enough, not yelling my answer to "that'll never happen, this is the way we've written," and then the other mock fellows switching to Hindi to cut me out of it.

And two years later, we added a new option to the enum and changed the return values of newly created domain objects that used it. All the tests passed, and the code failed when we ran the application, because the tests used mocks and didn't tell us what code depended upon that domain object that needed changing.

Anyway, after quite a while I began to think a little different, and come to a balance. I saw an example of a concrete class where we didn't care what values were in it, we only wanted to make sure a particular method was called, and there a mock made sense.

So, what I've come to is, mocking interfaces is fine. But with concrete classes, never mock the state of it, but if your test has nothing to do with the state, it's okay. Essentially, that's mocking just the interaction, and that's essentially the concrete class's "interface".

Wednesday, April 21, 2010

Caught or Catched?

Yeah, I know English, and not too bad, either.

Yesterday at work I was pair programming with a young teammate and we banged out some Java code like this:

try {
doSomething();
} catch (Exception e) {
processException();
}

And she was describing the flow while we were debugging to figure out why something wasn't working and she said "the exception should be catched here" and I automatically said "caught" and she said "sorry, caught".

But thinking about it a little more...

Maybe catched is okay. In this case, catch is a Java keyword that coincides with an English word. And describing what it's doing it could very well be that catched is a proper description of a keyword expressed in English.

For sure, if we wrote "caught" in the code it wouldn't compile...