In case you’ve been wondering why I haven’t kept my promise of doing a blog post every week, I had a two-week vacation just now. Originally, I’d planned to do some work on RPA Patterns anyways, but no plan survives contact with the enemy and I decided to relax more instead. But now we’re back to our regularly scheduled programming!
To lay the groundwork for a common understanding: I consider a framework to be an artifact that you use to speed up development and maintenance by providing a “harness” for your processes. This could be in the form of a template, or it could be simply a project you copy&paste whenever you create something new.
Frameworks help in three ways: first, they provide a consistent structure to your project, which can make it easier for others to read your code; second, they give you a headstart on boilerplate so you can begin implementing right away; third, they can crystallize an automation pattern for reuse.
Best practices are behavioral guidelines and prescriptive patterns about “how things should be done”. They can exist either on the scale of a team (“this is how we do things around here”) or on a community-level (“this is an accepted good solution to this particular problem”).
Best practices, similar to frameworks, help by giving guidance to developers (especially less experienced ones); ensuring consistency and therefore improving maintainability; and establish good habits that cause you to think twice before making certain kinds of stupid mistakes by violating them.
Say it with me: it’s complicated! In general, cultivating good habits and setting up common procedures makes a lot of sense. That said, I would consider overly heavy reliance on “best practices”, and trying to fit a square peg into a round hole by using frameworks for every project (even if they don’t really fit), to be a bad pattern.
Best practices and frameworks have their place. They are especially important for junior and citizen developers. But there is always the allure to switch off your brain, overuse them, and afterwards defend a bad decision by screaming “best practice” at the top of your voice. You all too often see developers blindly applying — or, worse, enforcing — “best practices” even when they don’t really fit the task at hand.This is the reason I tend to put “best practices” in scare quotes, in case you’re wondering
The domain where establishing common procedures is most useful is within your team or organization. In this context, frameworks and agreed-upon best practices generally allow you to assume that your colleagues are on the same page and thereby saves time. For example, it means you only have to add comments for things that deviate from convention rather than littering your code with them
Just be careful not to make them “laws” that always have to be followed even when there’s a good reason not to. And when you don’t follow them, put a comment in the code to explain why.
But very often, such procedures are not the result of careful thinking or an evolutionary improvement process, but just something Joe the dev came up with on the spot when asked. Joe gave his opinion on how a certain problem could be solved effectively, et voilà: “best practice”.
This is sadly all-too-common, especially in immature automation programs when consultants and other advisors are involved (yours truly is probably more often a source of this than I’d like in an ideal world). Junior devs learn by apprenticeship, and frequently don’t have the self-confidence to override the authoritative judgment from on-high, even if it was just pulled out of the prophet’s arse.
So if you’re a junior dev: be sure to drill into why your advisor made a suggestion until you fully understand and agree with itRandom sidenote: look up the “5 Whys” if you have time. If you’re an advisor, try to qualify your statements and make it clear that the solution you propose is contingent on certain characteristics of the problem. Always make trade-offs explicit.
One example that is, to my chagrin, enshrined in the UiPath Academy, is using the out-of-the-box Robotic Enterprise Framework (REF for short) for processes that don’t use queues. The academy teaches you how to modify the REF to handle an Excel file using DataTable rows as “transaction items”, but in my opinion this fails miserably.
To explain why, let’s delve into what REF does well: if you have a process that uses a queue, the REF gives you a fast way to set up the consumer side that executes the transactions. REF has error handling by default that isolates each transaction from the others, and provides a pattern for cleanly restarting target applications in case a transaction fails.
So REF is perfect for queues where each queue item has its own success flag and can be retried. But if you only have a bunch of lines in an Excel file and you want to execute them in one go on one robot, it becomes quite iffy. The idea for transactions in REF is that they are isolated, but the different rows in an Excel file are usually not well-isolated.
For instance, when you have an error in one transaction, REF would restart the target applications by default. So you either have to ignore large parts of REF (leading to unnecessary boilerplate), or need a flag for each row to mark its status.
In summary, while it’s possible to use REF for a process like this, I’d argue you can achieve better behavior with simpler code by using a For Each Row loop and custom error handling inside the loop.
Alternatively, just spend the approximately 0 minutes of additional effort to set up a queue, a producer that reads your Excel file, and a consumer using REF as it’s designed.While adding a producer is a small additional effort, not having to rework REF also saves you some time
This post was inspired by a discussion with one of our customers who asked me about frameworks. If you’re reading this, thanks for the idea! I hope this clarifies my position a little more.
That’s it for this week. I got back to working on the library pattern, which will teach you how to build a wrapper around a REST API, but can’t really give an ETA yet. See you next time.