One declaration to rule them all
As a full-stack developer you work with a lot of data. Data that is stored, displayed, and processed in the bowels of your program. A lot of times there is a lot of repetition and repetition. The SQL CRUD, the UI CRUD. And when you are a junior programmer who is clever, you start thinking dangerous thoughts… premature abstraction thoughts… I am doing the same thing over and over again. What if… we had another layer of indirection. Look at these objects I am displaying in grids and details. They are all stored in a similar way. What if I put them in a file, and then my program reads the file. And then it will do EVERYTHING!!!
I am a genius!!!!
So you write this file. It has a simple structure: list of objects. Each object has a list of properties. You add some metadata to each property. Like its type, and whether its required or optional. We assume optional and pat ourselves on the back for being clever. And then you write “the program”. It reads file and creates all tables, all the CRUD code, all of the UIs both list and detail. And the deed is done in seconds. This is so fast. I can’t believe no one has done this before. You show this to your coworkers people get excited. Except for the more grizzled programmer in the corner. She just smirks.
This is the way.
As you play around with your creation, new pathways form and you are cooking. We are adding new options to the properties. They can be required/not required. The validation for each is generated both in the UI, the service, and the DB!!! Why isn’t everyone doing this. You add default sort for the list view and the query. You add pagination to long lists. You find a screen that needs something different. You add a switch to the object to make the different thing happen. There is a complex object which needs a join. You add a virtual object with its custom query. You add support for the custom query. The magic config file grows. “the program” which generates code grows. Productivity dips.
What did we make
People are being unreasonable. There is too much variation. There is a complicated screen that does not conform to your metadata spec. We carve out a custom code feature for this. And so it goes. We work on the magic config file. We work on the code generator. Things are getting complicated fast. You approach the grizzled programmer for help. She explains what is happening. There is no judgment. She has made her own magic config file before.
Our very own programming environment
The grizzled programmer explains that we created a pre-compiler of sorts. We invented our own little programming language that gets translated into source code. But unlike existing languages, ours is tiny, undocumented, and understood by three people on the team. And then she asks the question that every engineer has to ask daily: What problem are we trying to solve? Here we are killing repetitive tasks. But those tasks were always the EASY part. It is the “custom” part where your application truly lives. And on top of that we were doing programming. We had some kind of definition file and a pre-compiler that assembled our magic config file into code. This is where some frameworks and ORMs get painful: they make the common path lovely, but the weird path is where your application actually lives.
Where to code
Generate code if you want. Scaffold the boring stuff. Let AI write the first draft of the CRUD endpoint. Fine.
But once the code exists, let it be code. Check it in. Refactor it. Test it. Let the next poor soul use the debugger instead of spelunking through your magic config file and the haunted machine that interprets it.
The grizzled programmer was not smirking because she lacked imagination.
She had seen the magic config file before.