I recently read an article about the worst kind of developer. I agree with the basic idea but wanted to add my thoughts on it.
Over time, I’ve seen developers seem invested in learning new things for the sake of new things, rather than getting better at existing approaches. Programming is like anything else — new isn’t always better. I have a Honda CRV which is not as easy to use as some cars I had before touch interfaces became popular. The touchscreen sometimes acts like I’m pressing different places on the screen when I’m not, making beeping noises and rotating the screens randomly. I have to stop and turn the car off and on to stop it. It has a configuration screen with every option disabled. It has a bizarre logic about locking and unlocking doors, which I never fully understood. I often wonder if the programmers who make software for cars have a driver’s license.
If I tried to ask 100 developers the following question, it’s highly unlikely that any of them, if any, would be able to answer it without searching the web:
Bob just graduated from programming school and has heard of MVC, but he’s not sure how to determine which code should be modeled, which code should be inspected, and which code should be controlled. How would you explain MVC code splitting to Bob?
It’s not a genius question, it’s actually very basic stuff. Here are some other good questions about other very basic things:
1. Why did the REST developers decide that POST should be created and Path should be updated?
The HTTP RFCs always state that a PUT is created or updated on a resource on the server so that a GET on that resource returns what the PUT is, and that a POST is basically a collection of anything that doesn’t fit into other verbs. The RFCs used to say that the POST URL was an indication of the operation, now they just say that POST is what you say it is.
Developers often talk about REST’s use of POST and PUT as if Jesus Christ Himself dictated this usage, as if there is no debate about it. I’ve never seen any legitimate reason why PUT can’t be created or updated like the RFC says and POST can be for non-CRUD stuff. Any real, complex system that is driven by customer demand for features is very likely to have some non-CRUD operations — integrations with other systems, calculations, searches (eg, a filter box that displays matches as you type, find search results on based on the input field), and so on.
By reserving POST for these types of other operations, you can immediately recognize anything that isn’t CRUD. Otherwise, you’ll end up with two uses of POST — mostly for creation, but now and then for other things.
2. Why do Java developers insist on Spring and JPA for absolutely every Java project without question?
Arguably, a microservice project should be, well, you know, micro. Micro is defined as an adjective meaning extremely small. When Spring and JPA take up more than 200MB of memory and take 10 seconds to run an almost empty project that barely writes a single row to a table, I don’t see a micro here.
Call me crazy, but maybe micro should apply to the whole approach, not just the number of lines: the amount of memory, the amount of handwritten code, the amount of time it takes a new employee to understand how the code works, etc. you don’t have to be weird about it, try 10 languages to see which uses the least RAM, just be reasonable.
In this case, Spring and JPA are designed for monolithic development, where you might have problems like the following:
- The constructor is mentioned 100 times in the code. Adding a new field requires modifying all 100 constructor calls to get the new field, but only one of those calls actually uses the new field. So dependency injection is useful.
- There are thousands of tables, with tens of thousands of queries, that need to be supported across multiple databases (eg Oracle and MSSQL), with use cases such as multi-tenancy and/or sharding. There comes a point where it’s just too much to do any other way, and JPA is a big help.
3. Why does every web application require large amounts of JS code?
When I started this business, we used JSP (Java Server Pages), which is a type of SSR (Server Side Rendering). Basically an HTML templating system that can populate slots with values that usually come from a database. This means that when users click the button, the entire page reloads, which is fast enough these days to be a blink of an eye.
The bank I’ve been using since about 2009 still uses some sort of SSR. As a customer, I don’t care that it’s a little blinking. It responds in about a second after each click, and I’ll only load maybe 12 pages in a session before logging out. I can’t find any complaint on the web about it.
I’ve seen a project “upgrade” from JSP to Angular. They had a lot of uncommented JSP code that no one knew how it worked, which became Angular code that no one knew how it worked. Some people would add new business logic to Angular, some would add it to Java code, and none of the project managers thought it was a good idea to make a decision about it.
No one ever explained why this upgrade was of any use or what it would do. The new features that were subsequently added were no more or less complex than those that came before, so continuing to use JSP would not present any problems. It seemed to be an upgrade for the sake of upgrading.
4. Why is everything new automatically much better than older approaches?
What’s wrong with tools used 10 or 15 years ago? After all, everything else works this way. Sure, we now have cars with touch screens, but they still use gas, tires, cloth or leather seats, glove box, steering wheel, glass, etc. The parts you touch every day to drive are basically the same as they were decades ago, with a few exceptions like touch screen and electric motors.
Why can’t we just use a simple way of mapping SQL tables to objects, like a code generator? Why can’t we still use HTML templating systems for a number of business applications that are mostly CRUD? Why can’t we use approaches that are only as complex as necessary for the existing system? I haven’t seen any real improvements in newer languages or tools that are significantly better in actual use, with a few exceptions like using containers.
5. Do you think other industries work this way?
I can tell you right now if engineers built things the way programmers do, I would never get in a car, walk under a bridge, or get on a plane. If doctors worked like that, I would be deathly afraid of every visit. So why do we do things this way? Is this really the best we can do?
I worked with a guy who shortly after being hired asked, “Why the hell do we have a mono repo?”. When I asked what was wrong with the monorepo, he couldn’t give any answer, but he convinced management that it had to change soon, apparently convinced with incredible passion that all microservices projects must be structured as separate repos per service. I’m not sure if it was him or someone else, but somehow it was determined that each project had to be deployed to its own container. These decisions were detrimental to the project in the following ways:
- One project was the definition of all objects to be sent over the wire. If the service object A is updated to require the new field, there is no compilation error anywhere that would indicate the need to update the constructor call. If service B calls A to create objects and no one thinks about it, then it’s likely that only service A has been updated to provide the new required field, and there’s a subtle, hard-to-find bug that might take a while for anyone to even notice notice.
- Your average corporate development box can handle maybe 15 tanks before it tips over and catches air. So quickly we lost local development in one of those irreparable ways that the team will never get it back.
- Any new developer would have to check dozens of repositories.
- No dependency information between repositories was tracked anywhere, making it unknown which subset of services must be running for service X to run on that one service. Combined with the inability to run all repositories locally it gives two equally nonsensical solutions for working on the X service:
- Use trial and error to figure out which subset X supports and run it locally
- Deploy each code change to the development server
When Alex talks about developers using extremely complex solutions like the ones he’s describing, it sounds to me like developers who are basically gunning for everything new and cool. It is very common in this business, every team has such people in it. This is not necessarily a huge problem in itself, but combined with an inability/unwillingness to ensure that other developers are fully capable of maintaining the system, and possibly an arrogance of “everything I say is the best”, and/or “only I can maintain this system,” it’s a killer combination that does far more harm than good.