2

I have a fairly good understanding of when data validation should and shouldn't exist when it comes when writing an application that is only dealt with by an end-user, and all the different tiers of the application and what code should check what (or, I would at least hope that I have a good idea).

However, as I've begun writing code that is not only going to interact with data provided by an end-user, but which will have developers (other than myself) specifying parameters and data to it, I've come across this conundrum numerous times. When should I validate data? When should I let it break? When is validation too little, or too comprehensive in scope? What about performance; how may it be hindered by additional layers of validation?

To provide a concrete example (out of many), one such case I had was when I was building a component that would manage a single-page web application. This component would accept a JSON object representing the web application's navigation map, in which were defined routes and the URLs at which page content resided for each route. It would use this tree of data to register the appropriate routes with a client-side Javascript router, and then handle loading and presenting pages when the right route was selected. When doing this, I encountered the following hypothetical scenario:

  1. Developer specifies two pages in the navigation map, let's say page-1 and page-2 for example.
  2. Developer defines page-1 to have the route #!/path.
  3. Developer also defines (mistakenly?) page-2 to have #!/path as its route.

The problem here is that, for the two pages in the example above, there's no way for my component to determine which of the two pages to load, as both have the same route: https://localhost/my-app/#!/path leads to two entirely different pages! My component would only be aware of the last page with that registered route, as it would overwrite the definition of the first page for that route.

At first, having shortly before worked with a bunch of code related to user input validation, I added logic into the recursive function which parsed the navigation tree to maintain a list of existing routes/paths, and if a conflict was found, append an incrementing number to the end to avoid conflicts. So, for example, page-1's route would stay #!/path, but when parsing the next page, the code would note that it already encountered #!/path as a route and rename the route to #!/path-2.

I didn't think much of it at the time. But recently, as I was going back to port the code to a new format, I was looking over this part of the initialization function and I wasn't sure if it was the right thing to do.

So far, the farthest I've come to a solution to instances like these, is the thought that perhaps both methods of conquering this problem, validation and the lack thereof, have their own pros and cons.

Also, and I feel this is important to note, I'm not only talking about situations where I fix an error for a developer. I find myself in the same situation when I need to decide when to check for an error in developer-provided data that is going to another component that is encapsulated within my component. When should I let the mistake go unchecked by my code, and let the library/component I'm using throw an error on its own? When should I step in and validate the data first before relaying it over?

The pros I've thought of are:

  1. The code continues to work even when an error is made, which may be desirable for an environment where downtime is a big problem.
  2. A developer can use the error-correction behavior to their advantage, and rely on it as a sort of shorthand, in the sense of having to code less.
  3. Similar to point 2, the developer doesn't have to watch their code using my API for errors/omissions/mistakes as strictly, which may fit their environment and the applications more flexibly, making it less likely for an issue to come up when using another product/component, or may just make it easier for them to manage the application if there are many similar lines of code using my API.

The cons I've thought of are:

  1. This could lead to undesired behavior as an error could go unnoticed for a long time without throwing any errors. Depending on the circumstances, it may make finding the source of the bug tougher to find.
  2. If developers begin relying on the error-correction mechanism I implement, that means that as more people depend on it working the way it does, the more likely it is for a new version of my element to break functionality for a lot of people. This may make improving my library/component/API tougher over time.
  3. Additional validation logic at such a low level may potentially hinder performance. In some cases, this may not be noticeable if at small scale, but when used at larger scale, may become a significant problem.
  4. Validation logic and error-correction logic further complicates my code. This may complicate maintenance as well, and with more moving parts, the more points of failure.

I'm not sure what's a good workflow to follow to get to a resolution in this case, and what rules/guidelines I should follow when working with such systems. I've certainly learned that developing a self-encapsulated program is much easier than developing an extensible system!

I've tried looking up information to help me figure out this problem, but so far the vast majority of what I've found relates only to working with end-user input, not developing APIs or libraries for other developers to use. With end-user-provided data, I need to be worried about my application breaking. But, in this case, I don't have that worry - instead it's the developer who wrote their own program using my library that will encounter an issue - with their program. How much should I be concerned with their application breaking due to their own mistake?

So, in conclusion:

  • What steps should I follow to determine, when developing APIs or extensible components, when I should or when I should not correct mistakes validate data provided by other developers?
  • How should I determine when my code should let 3rd-party data go unchecked to a deeper API/program component not written by me to let it throw an error, and when it should step in and check for errors first before relaying the data?

Footnote:

To be clear, I understand there isn't always (or, rather, is rarely) a one-size-fits-all solution, and I am not asking for the "best option." Really what I'm looking to understand is how do I evaluate which route to take in this case, and what variables may I be not considering? From the experience of others who have worked with similar situations, what did you learn along the way, and what should I do to figure this problem out? I'm coming at this without any practical experience working in an office or on a project team, only experience with the technology itself. The more I've developed, the more I've learned that there is far more to programming than just the code itself.

  • recommended reading: Why is asking a question on “best practice” a bad thing? – gnat May 21 '15 at 5:02
  • @gnat Thanks for the link; I haven't asked questions here before, just lurked and tried answering one over on SO. Hopefully my head will prove itself to be (a bit) more than a resonant cavity. x) I went ahead and edited my post to avoid that generic phrase. – Adaline Simonian May 21 '15 at 5:05
4

Validation of input parameters/data should be performed whenever the data can come from an untrusted source. To be on the safe side, if anyone outside the development team can supply data to an interface, then that interface should validate its inputs.

The more interesting part of the question is what to do when the validation finds a problem.

First of all, don't presume you know what input was meant. This also means you shouldn't try to autocorrect the provided input. For normal text on an interactive interface, you could make suggestions for (spelling) corrections, but you should always give the user the final authority on what data they want to provide to the interface.

If the validation error is such that your software can't operate in a meaningful way with that input, then you should generate an error and either keep working with the old data you already have or refuse to work at all.

If the validation error is such that your software can operate, but with some sub-optimal or surprising results, then it would be best to accept the data, but also indicate a warning that there are problems with it. Where to draw the line depends on your requirements.

For example, with the configuration where two pages have the same route, you could flag that as a warning, and otherwise accept the configuration. This has the effect that, if the user chooses to go to 'page 1', they appear to end up on 'page 2', but that might just be the desired behavior.

When providing data to a third-party API, assume they will do their validation in the harshest possible way: the application terminates if the preconditions for calling a function are not met.

4

I've been developing extensible software for a long time now. I've also been on the other side. One thing I've learned is that you want libraries you use to "Fail fast". What that means is, it should break my software as soon as possible if something is wrong. If you can (which in this case I presume you can't) break at compile time. If not, throw an exception when debugging and make it as clear as possible as to what is wrong. Don't hide errors at debugging time. Then if you need to be very robust, at release time, don't thrown an exception, but do log a clear warning as to what is going on.

All this leads to a very usable, self debuggable third party library, which is what you, and any developers using your code, want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.