Software Engineering with Mel and Velimir
10 Commandm… Recommendations for Software Analysts, Designers and Developers
"The Lord Jehovah has given unto you these fifteen... Oy... ten! TEN Commandments! For all to obey!"
Mel Brooks (History of the World)
APEX blog without APEX
After almost 20 years spent in the world of (mainly, but not exclusively Oracle) technology and wearing different hats (architect, consultant, developer…), I dared to put in writing general principles that I wish I had known at the very beginning of my professional journey. I feel that today, there is a lot of information about "tips and tricks," but more often than not, we lack recommendations about core principles that software engineering is built upon.
Of course, I have not really discovered these principles on my own. I only tend to apply them as consistently as possible. Still, most of them are learned during the years of working with and/or learning from Marjan, Nataša, Alex, Keny, Sylvain, Anton, Steven, Rich, Jurgen (...), who will recognize their influence as they read along.
If I were younger and prettier, I would make YouTube reels or TikTok shorts (or was it vice-versa?) out of this and reach a wider audience. However, I will intentionally ignore the "TLDR" danger as this is my first blog post, and I am not sure I will ever be motivated enough to write the second one, so all topics that crossed my mind are here.
After all, this might be the only blog (post) about Oracle APEX that does not mention APEX at all.
#1. Ask "Why?"
During the requirements collection sessions, often, there is a thin line between users providing requirements as opposed to users attempting to provide solutions. You should care only about the former. If users can "justify" their requirements by describing the business need, they are probably valid. On the other hand, if they describe requirements as a "commonly used way to achieve some goal," watch out, as there might be a better alternative just because the real business need and perceived way of fulfilling it might not be aligned. In other words, do not be a "yes boss" consultant (I'm not sure if the term exists, but I heard it recently from an owner of a successful IT company, and I love it).
Years ago, I became part of the ongoing project, replacing the actual technical lead. At the first meeting with the client, by posing the question "Why," I led them to conclude that already accepted and budgeted requirements were not really needed and would not produce the perceived benefit. We did not get the expected revenue from implementing these changes. Still, subsequently, we got ten times more work from this client who trusted us because our relationship was honest and professional from the very beginning.
#2. Mind the (physical) process
Typically, the software supports some business processes that take place in the real world, even when you are just starting to talk about the future application. You have to remember the physical actions while designing parts of the process that will be assisted by the new application. Usually, you will want to recognize and draw all process steps (my preference for notation is BPMN), including ones that will not change after the client starts using software (for example, "The clerk gets the document from the courier"). While doing that, you will want to answer the following questions:
Who should perform the specific step? What happens in case of unavailability or inaction?
What should they do? Should it be done in the application or not?
How do they know that something should be done (for example, the action should be taken when the courier delivers the document or when notification by the software is received)?
If there is a decision to make, is there a way to collect all the information needed to make that decision at the given time?
If there is an action in the software to take, how convenient is it to navigate to the relevant page and record, having the information available at the given point in time?
What happens in case of human errors (assume that the user can make the wrong call even after many dramatic warnings, and at the end of the day, after the user's apologies, it will be your responsibility to provide the workaround or data fix)?
Finally, do your best to explain the process to the client (not just to deliver the document they might need help reading and understanding correctly). Be transparent and let them know that their participation in the project execution is also crucial, and address the common misconception that you will do it all alone and deliver the perfect piece of software after initial meetings and without any other questions or interim feedback.
#3. Make suggestions
When discussing the client's requirements, it is always a good idea to present any suggestions on how they can be fulfilled. First of all, you can guide the client to a solution that is easier to build or maintain and, at the same time, presents a good fit for their business needs. Second of all, by presenting suggestions, you take the initiative, and these suggestions talk more about your knowledge and experience than any reference list you might show. If there is more than one suggestion for a particular use case, be sure to be transparent and point to the pros and cons of each of them (needed effort/price, impact on other functionalities, more or less uncovered cases, different deadlines, different level of client's engagement…), and allow your client to make the informed decision (and sometimes that decision will not be the one that you might consider "ideal," which is still acceptable if it is created based on enough data).
#4. Mind the basics
Nowadays, by following trends of catchphrases, "hooks," and "modernization," traditional concepts are often put aside, considered "outdated," or simply "boring." This statement is no less true for the software development area, including the basics of database design – arguably the foundation of any successful software project. Namely, do not forget that database design is founded on strict mathematical rules (in my University course, I have not seen a SQL statement for the first three months of lecturing), and as such, fully justify the "engineering" part in the "software engineering" title. From the very beginning of your project, keep in mind normal forms, constraints, indexes (…) – even when, at a given point of time, it looks like they are "not worthy" of time investment, as there are "not too many entities or not too many functionalities." Over time, functionalities might evolve, and if you create technological debt at the very beginning by ignoring the root principles, that decision will eventually hunt you down. If there is a need to deviate from standards, think twice. If the need is still there, be aware that you made a conscious decision and document it so it can be revisited later.
#5. If it happens "rarely", it still happens
Sometimes, you will hear from users that a certain situation "never happens... um... almost never happens ". According to Murphy and my own experience, the probability of such an event on the first day of Go-Live is inverse to the described likelihood of the event in general. Regarding software design, "almost never "does not differ too much from "frequently enough," as any of these situations has to be handled. However, you can take one of two valid approaches:
Incorporate handling of events that "almost never" happen in your software design, as if they happen regularly (which will somehow reduce the probability of seeing them at all) or
Make the client aware that these particular events are not supported (i.e., the software is entirely ignorant of these). Still, with clear recommendations of workaround in case they happen (even if the workaround is so unpleasant as "ask support to fix your data manually").
Obviously, the decision should depend on the estimated impact of enhanced design on the project budget and timeframes.
#6. Looks matter… or not?
If you come from the ERP world, you might notice that some of the most famous solutions have some of the worst UX, and they are entirely opposite from being anything near user-friendly. More than once, I ended up explaining to clients that "UX is less important than the concept itself," "UI is merely a makeup, while functionality is the essence”, and so on. While this might be the necessary speech for off-the-shelf products, do not fall into the trap of applying it as the general principle in software development. Otherwise, your clients will hate your application and consequently will abandon it.
On the other hand, when designing UI/UX, do not show off. Clients typically do not care about your insane CSS and JS skills, and that fancy animation that attracts "wows" during the first presentation will become annoying after the third session, as it takes time to load and does not bring additional value. Remember that you do not develop applications for your colleague developers to be amused but to allow clients to fulfill their business needs with the least amount of stress and distraction. In that sense, make sure that your application is performant and that it guides users to the next steps that produce the most sense within a clean layout (if you still need these "wows," keep one or two fancy pages for the sake of new presentations, but feel free to hide them deep in the user menu).
#7. Oh my God… It is full of users.
While developing the application, you will usually be the only person testing it. Even during the QA, the process will often involve one or two testers per functionality. However, remember that in the real world, many people can initiate transactions simultaneously, which can be mutually dependent (or even related to the same object instances). In this regard, we can differentiate two cases:
Imagine two users trying to deduct a certain amount from the same bank account simultaneously. This action must not be allowed under any circumstances. You might want to lock the resource (bank account record) during the execution of each transaction and release the lock only after the transaction is committed (knowing that such locks might harm performance and rightfully understanding that avoiding data corruption is, in this case, more important than a slightly faster response).
On the other hand, if two users are trying to update the nickname or favorite color of the employee, you might just "let it go," as the database will save the latter update… however, even in this case, MD5 hash comparison can be your friend.
Remember the concurrency even when users ask for support, claiming their data is corrupted. Just because you can not replicate the reported issue (as you are the only one testing at the given point in time) does not mean it did not happen in production (with multiple concurrent users).
#8. Validate the already "validated" data
One of the worst things that can happen in a business application is data corruption. If you allow corrupted data to go in, usually there will be no way to fix it, at least without being transparent to the client, saying that your application allowed something that should not have been allowed.
To prevent data corruption, you should implement validations at different levels:
The first one is, obviously, UI level – for example, you will render only buttons that the user is allowed to click at the given point in time.
However, developers with less experience sometimes forget that the moment of rendering the page is not the same as the moment of action execution ("clicking the button"). So, even if you rendered the button because conditions were such that they allowed the user to click at the moment of rendering, it is not necessarily true that conditions did not change before the moment of clicking the button (not to mention the possibility of unwanted modifications at the client's browser that we forgot to prevent). Ergo, the same set of validations should also be executed at the backend level.
Finally, there might be different ways to put the data in the application, including executing manual SQL statements by support team members. To enforce the applicable set of rules even then, remember to design your database model with all constraints in place, as if validation was never done at the application level.
#9. You need your software more than your customer does
Yes... that is right. The customer had their business processes in place before you came, and in the worst-case scenario, they can be continued even without your (or any other) software. However, you are the one who makes a living by implementing and supporting software solutions, so it is in your best interest to make them good enough for your customers to be fully satisfied.
Does it occur sometimes that software is implemented according to the specification and even paid for but never goes live? It's common, but it's still a problem because you will not be able to achieve revenue by providing support services in years to come (and in reality, this is often the primary source of income, together with change requests management). Always do your best to assist your customer in the software adoption and change management period, even if you are not officially required to, as this is in your best interest.
Is software implemented and live but with many bugs, requiring frequent interventions by the support team? Again, this is relatively common and far less than ideal, as by failing to escape the technological debt, you fail to reduce the cost of support, thus making less revenue. Never ignore that you will (hopefully) someday support the software you build, and think twice before applying "quick and dirty workarounds" or failing to address potential performance issues at early stages. Stable software with fewer functionalities is often the better choice than "beta" software with lots of perks, as it builds a better foundation for a long-term relationship with the customer.
#10. Simplicity is the ultimate sophistication
This quote is attributed to Leonardo da Vinci, and even though I can't be sure that he is the real author, it is the most precise and concise guideline for software engineers. If you did not find traces of it in all other recommendations, I failed to transfer the genuine sentiment while writing this post.
At the very end, I will break the promise about "Oracle APEX that does not mention APEX at all," and I will say that precisely using Oracle APEX allows you to follow this, arguably the most important, recommendation.
Instead of Conclusion
If you reached this point without skipping too many things, I would like to thank you and congratulate you for your patience.
I am aware that reactions to individual topics might vary from "Thank you, mister Obvious" to "This is simply wrong" (with occasional "Nice"-s). However, I would still appreciate any feedback (such as your experience, if you have a favorite topic, if there is something you would add, etc.).
I will do my best to respond.