In the late 90’s and early 2000’s, an entire industry was launched to get companies and governments to switch from their 60’s mainframe systems to something modern. “Modern” in those days usually meant Java. For example, I’ve attended vendor presentations that promised you could take your mainframe, put a SOAP web service on it, and then gradually migrate modules from the mainframe to Java Enterprise Edition. Over the years, I’ve seen exactly 0 successful migrations like this – they usually end up trying it for a few years, then bite the bullet and do a major rewrite.
That’s the situation ML was in: a state government wanted to replace its COBOL mainframe monster with a “maintainable” J2EE/WebSphere based application. Gone would be the 3270 stupid terminals, and here would be desktop computers with web browsers.
ML’s team did the initial design work, with which the state was very satisfied. But the actual development work shocked the government sticker, so they decided to take the design from ML’s company and send it to the lowest bidder overseas to actually do the development.
By the way, this was another popular way of thinking in the early 00s: you could design your software as a set of UML diagrams and then hand them off to the cheapest coder you could hire, and voila, you’d have working software (and someday soon, be able to you’ll just generate the code and you don’t need a developer at all! ANY DAY NOW).
Now, this code is old and predates the generic form in Java, so the usage is ArrayList
s not WTF. But the programmer’s approach to polymorphism is.
public class Applicant extends Person
.
.
.
public class ApplicantValidator
public void validateApplicantList(List listOfApplicants) throws ValidationException
List listOfPersons = new ArrayList();
Iterator i = listOfApplicants.iterator();
while (i.hasNext())
Applicant a = (Applicant) i.next();
Person p = (Person) a;
listOfPersons.add(p);
PersonValidator.getInstance().validatePersonList(listOfPersons);
Here you see Applicant
is a subclass of Person
. We also see an ApplicantValidator
class, which needs to check whether the requester objects are valid – and in order to do this, they must be treated as valid Person
objects.
To do this, we iterate through our list of apps (which, it’s worth noting, are treated as Object
since we don’t have generics), switch them to Applicant
s, then throw Applicant
variable for Person
and then create a list Person
s- which again, without generics, is just a list Object
s. Then we forward that list of people validatePersonList
.
All this is unnecessary and shows a lack of understanding of the language being used. This block could be written more clearly as: PersonValidator.getInstance().validatePersonList(listOfApplicants);
This gives us the same result with much less effort.
While much of the code coming from the offshore team was actually solid, it contained so much nonsense like this, so much misunderstanding of the design, and so many bugs that the country kept going back to ML’s company to fix the problems. Between paying the offshore team to do the work and then the ML team to fix the work, the whole project cost a lot more than if they had hired the ML team in the first place.
But developers were still charging at a lower rate than ML’s team, which meant managers were responsible more had to brag about the savings, even though they exceeded the project budget. “Imagine how much it would cost if we I did not have gone with cheaper labor?”