At DevExpress, we frequently hear about issues customers have with our updates. I personally hear about these when I teach our training classes or meet customers at events. I felt like saying a few words about this and I decided to post them here rather than on the DevExpress blogs because they represent my personal opinion and advice — I wouldn’t say (or think) they would conflict with any “official” company line, if there was one on this, but I also didn’t want to risk the impression that my points and personal opinions form such a company line. When I say “we” in this post, I’m not implying that anybody else would have to share my opinions, it’s simply a shortcut for “myself and others at DevExpress”.
As you probably know, DevExpress releases major and minor updates. The major ones use the first two parts of the version number: 15.2 or 16.1. The minor updates use the third part, as in 15.2.4, 15.2.5. Major updates bring major new features and large changes, minor updates are bug fix releases only. Both types of updates can introduce breaking changes, though we try to keep this to an absolute minimum for minor updates — unfortunately, fixing buggy behavior can still be a breaking change!
Among the complaints we hear sometimes are those that point out mistakes we make in our updates. I think everybody at DevExpress would readily concede that we make mistakes — of course we do, we have no greater expectation to release bug-free software than anybody else in the business. We also sometimes make procedural mistakes, again just like anybody else. Occasionally changes creep into minor releases that should have been left for a major update. Occasionally there are regressions. This happens in spite of the heavy testing that is done on each release, in spite of the detailed plans and procedures we have established over many years to prevent mistakes. We gladly accept criticism on such issues and we try to improve continuously.
From my own position of being closely involved with the company, as well as watching DevExpress from the outside, both for many years, I can attest to the professionalism of every single person there, and their readiness and eagerness to admit errors, fix problems and find solutions. Of course there are also comments that just ask us not to update so frequently, not to have breaking changes ever, or similar. In the end, updates are expected, since they deliver the value our customers are paying for in their subscriptions. We try our best not to break existing APIs if we don’t have to, but we also follow the same best practices as everybody else to keep down technical debt, provide obvious entry and extension points, and generally evolve our software to keep up with general industry developments.
But then… With all that said, here is an artificial support request which points out a few issues we’re also frequently facing:
I have a solution that was based on 14.1.6 and I just updated to 15.2.3. Now my solution doesn’t build correctly and my application is broken.
In reality, requests like these are sometimes complemented by statements like “you guys suck” or “I can’t work like this”. I’m leaving these out here… What problems are we looking at here? This request describes a situation where a customer tries to update from one major to another while skipping a few releases in between. While I understand the desire to do this to save time, I don’t recommend using that approach.
Here are some guidelines I often explain during my training classes:
Guideline 1: Follow major releases
There are several reasons for this recommendation. Each major release may have changes, potentially breaking ones, that apply to your code. The effects of such changes accumulating when you try to skip major versions are unpredictable, and it is hard to understand the cause of a particular issue by looking at the combined outcome. We also follow a pattern where elements may be marked Obsolete
in one major release and then removed down the road (in another major, to be clear), and by skipping major versions you may miss the resulting compiler warnings and helpful messages entirely.
I also don’t agree that you end up saving time using this approach. The work required to make a big version jump can sometimes be quite daunting, whereas that required to go from one major to the next is much quicker and easier. Eventually, a certain amount of work will have to be done — the difference is doing it all at once vs a little bit every now and then.
Another reason why it’s easier to follow major versions is that the DevExpress support guys and girls will be able to help more quickly if you run into trouble. Around the timeframe when a new major version becomes available, they will be very familiar with questions arising from the update and they can answer quickly or create additional supporting knowledge base samples as necessary.
Guideline 2: Make sure to check out breaking changes and work through them
We go to great lengths to document changes and provide instructions for required modifications to customer code. On our version history page, you can find all these documents for your reference. As part of a DevExpress update, I recommend you read these documents carefully and work through them as they apply to your code. In reality, chances of any particular change affecting you are really quite slim, given the vast number of components and libraries in our suite. This is your primary resource to stay on top of what happens in updates!
Here’s a second artificial support request:
Your recent minor update 15.2.4 was meant to fix issue X. Now my customer tells me their old problem is still there and also my application feature Y doesn’t work correctly anymore due to some other issue.
The main recommendation I derive from this should be quite obvious.
Guideline 3: Test your own software
Keep in mind that the software you deliver to your customers is your own, and what you deliver defines how your customers view you and your business. If your software ends up in your customers’ hands with bugs, we can certainly apologize for any role we played in introducing these bugs, but you’ll also have to accept responsibility for not finding out that your software didn’t work right before you delivered it. The technical reality is that our components are extremely flexible, and in spite of the fact that we are already aware of thousands of use cases for individual components, our customers keep coming up with new ones we have never thought of. We have vast experience in our field and we are very good at anticipating how our products will be used. However, that experience has also taught me that every customer always thinks they’re doing things exactly like everybody else and therefor, surely, that piece of functionality implemented on top of one of our products doesn’t require specific testing.
Unfortunately, the number of possible permutations is enormous and more often than not, somebody who experiences unexpected behavior has found an edge case that was not previously covered. Logically, this also makes sense to me: in the end our customers are developing unique software, establishing their own individual selling points, striving to do things differently.
Another issue with testing is obviously that it takes time and effort. So here’s one more recommendation, perhaps equally obvious to the above. It’s much more general than the other ones, of great importance to software development in this day and age, and highly applicable to the handling of 3rd party building blocks used in your code.
Guideline 4: Invest in automated tests
It is absolutely imperative these days to take the pain out of testing. It should be automatic. You save enormous amounts of time and money by establishing a strong suite of automated tests for your software. Yes, I maintain this is even true for the usual “enormous chunk of legacy code” applications out there. If you develop, evolve and change your software over time, even if it’s just by updating 3rd party component suites, you need to test, test well and test frequently. The goal of achieving good coverage with automated tests actually helps you in the process of refactoring a legacy piece of code towards maintainability.
Final words
There is no excuse for delivering untested software. We do our best with our libraries, and due to the scope of our testing, we occasionally find issues in the underlying infrastructure of the .NET Framework (or others, of course). Feel free to let us know if you think we’re not doing a good enough job — change is constant, and hopefully so is improvement. But do your own job as well! Make sure your own software is up to your standards before delivering it! Don’t fall into the trap of thinking that somebody else’s code is better than your own!