Saturday, June 29, 2019

You're doing it wrong

Attention software developers: you're doing it wrong.

To be more specific, you need to be doing these things, and you're not.

Don't block the UI thread!


No matter what the application is, not matter what you're doing, do not block the UI! A "Please Wait" dialog or screen is trivial to code and makes the user experience so much better. You can never assume that an operation will always execute quick enough not to block. It always will under some scenario.

Catch everything!


There is no excuse (at least in the .NET world) to allow an exception to bubble up so far that the application crashes. There is always a way to catch exceptions at the highest level. Even if there's no way to recover, exit gracefully.

And don't restart the app without warning. Visual Studio and SQL Server Management Studio are big offenders here. If recycling is the only way to recover, fine, but don't just do it without telling me!


Always format numbers.


I'm so sick of having to squint at 41095809 and mentally insert the commas (or whatever the delimiter is in your culture). Having the code format this kind of output is so trivial. Software is supposed to make our lives easier. If you don't do this you have failed.

Don't confuse a pattern with a function.


Okay this one's not quite so obvious. There are times when you have to do a similar thing in lots of places. The natural inclination is to make this into a function/method/class. This is a good instinct! Don't repeat yourself! But it can be taken too far. Some things look similar but have enough differences that trying to create a generic base for them just makes the code way more complicated.

To put it another way, you wouldn't try to write one ForEach() function that handles all loop cases. It would quickly become a monster. Looping is a pattern, not a function.


Let's be clear: I have committed all these sins and will again. Learn from my fail, and we can all stop doing it wrong.

Saturday, February 2, 2019

No junctions with SQL Server FILESTREAM columns

We're using a SQL Server table has a FILESTREAM column, and we have some tests to verify reading & writing to this column. A little while back I started getting this error when I tried to run the tests that accessed this column:

System.ComponentModel.Win32Exception: The system cannot find the path specified.

I found a lot of information out there about this error: it can be caused by permission issues, by bugs in earlier version of SQL Server, and sometimes registry & setup errors. But none of the remedies they suggested worked: the SQL Server process had full control of all the directories involved, the registry hacks didn't change anything, and we're using 2017 Developer Edition. I thought it might be because I'd renamed by laptop (the test SQL Server instance is local), but after fixing the server name within SQL Server the error kept happening.

Then I remembered: our test database setup script has hard-coded full paths for the database files and I had set up a file junction on my laptop because I'd wanted it live in a different folder but didn't want to break compatibility. I wondered if that could be the culprit. I deleted the existing test database and re-created it in a different place altogether that didn't involve the junction. Sure enough, things started working! (I then re-wrote the setup script to use the default directories.)

I don't know if using junctions with FILESTREAM has a bug, is not supported, or I just didn't have all the permissions set up correctly, but either way the two things did not place nice together.

Thursday, August 16, 2018

Stop describing me!

Anyone who's ever worked in software knows how difficult it is to keep the code and the documentation in agreement. It's all too common to find errors in documentation, and not just typos, but misleading or even just false statements. This is (generally) not the result of malice, laziness, or stupidity, but is rather a natural consequence of trying to keep two unrelated things in sync with each other. Programming and natural languages are just not similar enough to make this a simple or automatic task. It's one reason experienced programmers are prone to say that all code comments are lies.

Additionally, documentation is far too often a crutch used to make up for the fact that the design is not intuitive. As Chip Camden once said, "Documentation helps, but documentation is not the solution - simplicity is." That doesn't mean that software can't be doing complex things - doing complex things is the whole point! What it means is that the interfaces to software, whether they be APIs or GUIs, have to make the complex thing simple.

Documentation then is typically a symptom of poor design and a difficult symptom to manage at that. But how then do we communicate the what and why of a software system?

The answer is self-documenting systems. "Self-documenting system" sounds like the tagline of some new tool somebody's trying to sell, but it's actually a design philosophy. It's an approach that says: make the endpoints, buttons, menu options, links, namespaces, class, method, parameter, and property names so obvious as to their purpose & function that, for the majority of them, documentation would be redundant.

The term "redundant" is used very deliberately here - it's not that documentation is never warranted, it's that we should seek to make it unnecessary, for the reasons mentioned above. There will still need to be a few bits of explanation here and there, but they'll be few, so maintaining them won't be a big burden, and they'll be very targeted, so it'll be very obvious when they need to be updated. (By targeted, I mean they'll be either high-level descriptions of the unit as a whole, or notes on some edge cases.)

Self-documenting systems lead us to the Principle of Minimum Necessary Documentation, which states:

There is an inverse relationship between how well designed something is and how much documentation it needs.

The term "inverse" is also used very deliberately. The inverse of infinity is not zero - it's darn near close to it, but it's not actually nothing. A perfect system needs no documentation, but there are no perfect systems, so there is no system that can have zero documentation, no matter how well designed it is. But for a well-designed system, a README file or some tooltips will probably suffice.

But do not assume from this that a project with no documentation except a README is well-designed, or that you can get away with just throwing together a README and taking no other thought for what's going on. Note the principle says "how much documentation it needs" not how much it has. If users have cause to say "the documentation has been skimped on", then the design is poor and no crutch was provided, which is even worse than a bad design band-aided with documentation. Intuitive, self-documenting design is the critical factor, not the documentation itself.

Now, there are a few caveats & clarifications that should be mentioned:
  • 'Self-documenting' is often used in connection with test-driven development. There is a vein of thought that says the tests should be the mechanism for documenting the code. This is a very good approach to take, but tests cannot serve as the user documentation. If the project is a public one, expecting people to read the tests is not realistic, and even with an internal project, understanding the guts of how a component works is often beyond the scope of the task at hand. Tests can and should be the developer documentation, and complete test coverage is critically important to developing robust software, but a test suite is typically too large and specialized to be the sole documentation.
  • Most systems have a fairly obvious surface. It may not be instantly obvious what a class structure or API or SDK or GUI does, but it's usually pretty easy to see what it has. There are interfaces though that don't have an easily reflectable surface, such as command-line tools. At first blush, it might seem that this is a place where more documentation is a necessary evil. Certainly there are a lot of tools that believe extensive documentation is preferable to abstraction (git, I'm looking at you). But the principle does still apply here. It is still incumbent on the developer to make the behavior intuitive (typically by following conventions), and to make the options easily discoverable. There are a myriad of ways to approach this, and it depends a lot on how flexible the tool needs to be. It requires more work, but that's our job: to make it easy to use.
It's as I've said before: deal with things directly. Don't build hedges around them, because it just takes more work and isn't as effective. Don't worry about documentation unless there truly is no other way to get the point across. Focus instead of making your code as intuitive and straightforward as possible, as this is the greatest programming good.

Thursday, May 11, 2017

Adventures in SQL Server Licensing

Over the weekend, we upgraded from SQL Server Standard Edition to Enterprise Edition. (We also upgraded from 2008 to 2016, hooray!) There were of course a lot of factors driving this, but one of the more compelling ones was the desire to utilize all the processors on the host machine. SQL Server Standard is limited to 24 logical processors (official source: Compute Capacity Limits by Edition of SQL Server - see the chart near the bottom of the article). SQL Server Enterprise Edition however can use as many processors as the host machine has to offer (see same source). Our host machine has 96 logical processors, so we were only using a quarter of the capacity, so this was an important jump forward.

Imagine our surprise and alarm to come in the morning after the upgrade to see that the server was performing very poorly. We quickly discovered that it was still not using all the processors, and even worse, it had now dropped down to only 20!

After some research, we were able to discover that we had installed the wrong kind of Enterprise Edition! Enterprise Edition comes in two kinds: Server/CAL and Core-based. CAL stands for Client Access Licensing, and is a licensing model that caps how many clients can connect to the server at a time. As you can imagine, this is hard to estimate and significantly limits scalability, so it is not a popular option. Almost everyone goes for Core-based licensing, and that's what we had purchased and needed, but it was not what we had installed. Server/CAL Enterprise Edition is limited to 20 cores (40 if using hyperthreading) [see the footnote to the afore-mentioned chart].

To confirm that this was our issue, we checked the SQL Server logs at when the server started up. We saw this line (emphasis added):
SQL Server detected 4 sockets with 24 cores per socket and 24 logical processors per socket, 96 total logical processors; using 20 logical processors based on SQL Server licensing.
We also checked the edition by running SELECT SERVERPROPERTY('edition') and got Enterprise Edition (64-bit).  This seemed okay, until we realized that we needed Enterprise Edition: Core-based Licensing (64-bit).

We were afraid that we were going to have to reinstall SQL Server, but the fix turned out to be simpler than that. We had to download the right installer, the one for SQL Server 2016 Enterprise Edition Core, and then do an Edition Upgrade from the Maintenance menu. This article has a good walkthrough of how to do it: see the section "UPGRADING SQL SERVER 2008." The screenshots are from an older version of the installer, and it suggests you'll have to enter the product key manually, which you probably won't have to, it will probably be auto-filled. (This MS Docs article gives a more up-to-date and complete procedure, but it doesn't have any accompanying visuals.)

Once we reached the end of the wizard and clicked "Upgrade", the change was very quick, and once the SQL Server service was restarted, it went up to using all 96 cores! We were able to confirm that the edition was now Enterprise Edition: Core-based Licensing (64-bit), and saw the startup message changed to:
SQL Server detected 4 sockets with 24 cores per socket and 24 logical processors per socket, 96 total logical processors; using 96 logical processors based on SQL Server licensing.
It was of course a huge relief to figure this out, but it was hardly a quick process. We were down for almost three hours. So I'm putting this out there in the hopes that other folks won't have to go through the same pain. And it seems like a lot of people have felt this pain - Microsoft clearly needs to do a much better job of labeling and explaining this quirk of SQL Server installation. (Microsoft needs to massively streamline and simplify all SQL Server licensing, but that's a topic for another time.)

So, final take-aways:
  1. When installing SQL Server Enterprise edition, make certain you have the right installer for the license type you have purchased, whether it be Server/CAL or Core-base Licensing.
  2. If you find you have installed the wrong type of SQL Server Enterprise Edition, you can correct the issue by doing an Edition Upgrade from the correct installer.
  3. SQL Server licensing is way too complex.
(Thanks to this DBA.SE answer and this blog post that helped guide us down the right path.)

Saturday, September 17, 2016

4 Things They Don't Teach You About Programming

1. Most of your time will be spent debugging someone else's code, not writing your own.

When you're learning how to program, you write everything from scratch (sometimes to ridiculous lengths). This is good - it's how you learn. But it can set you up for a unrealistic expectations about what real-world programming is like. Most programming involves digging into something someone else wrote years ago and figuring it out because no one really knows anything about it except that it works, but now they need you to change some part of it. It's why programming experts often advise you to code like the person who'll read your code next is a violent psychopath who knows where you live, because one day you will be that person, and you don't want to be driven quite that insane.

See also Orthogonality and the DRY Principle, featuring the Right Honorable Dave Thomas.

2. 90% of programming is converting data from one format to another.

When learning to program, you write Cool Things - binary tree balancers, XML parsers, chess games, even simple databases & operating systems. But when you get a job, most of that stuff is already done, and your job will be to convert one thing into another thing. You gotta convert your objects into database tables. You gotta convert the data coming back from the API into HTML. You gotta convert the values from that ancient file format into something usable. And the list goes on and on.

This doesn't mean that programming is all drudgery! There are lots of interesting, even exciting challenges in this area. It's just not something they cover much in training.

3. Polymorphism isn't that important.

Polymorphism is important: it's one of the most powerful tools you've got in your toolbelt to make software loosely coupled and maintainable. But when you take programming courses they make it seem like programming is the task of building the Unified Class Structure of Everything. In reality, abstract classes and complex inheritance have relatively few uses. Interfaces are the most important aspect of polymorphism, and any programmer worth their salt should know how to use them extremely well. But most stuff beyond that isn't that important.

4. Programming will never stop being a source of wonder.

I've been writing computer programs for 20 years now, and still there are those moments when it works and I go, "no way, I did it!" There's still a bit of magic in it, even after understanding all the math and electricity that's involved, and I've found that that's true for most programmers. It never stops just being cool.

Friday, July 15, 2016

Poking just the wrong spot, or How Two Minor Bugs Generated Some Very Scary Error Messages

So we had a stored procedure that started timing out occasionally in production. We determined the issue was parameter sniffing, so we decided to just add a OPTION RECOMPILE to the query inside it. It was tested, and released.

Upon release however, we starting get an extremely scary-looking error message that was even being entered in the SQL Server log:

SQL Server Assertion: File: <op_ppqte.cpp>, line=12258 Failed Assertion = 'llSkip >= 0'. This error may be timing-related. If the error persists after rerunning the statement, use DBCC CHECKDB to check the database for structural integrity, or restart the server to ensure in-memory data structures are not corrupted.

Naturally we rushed to figure out what was going on. Researching the issue didn't turn up much though - we found a few KB articles that seemed related (like this one and this one), but nothing that described it exactly. As it seemed to be a bug in SQL Server itself, we installed the latest Cumulative Update for SQL Server 2014, but it did not change anything.

As we dug in to try to find a workaround, we discovered there was a different error that had been occurring before we released the change that we had not noticed before:

The offset specified in a OFFSET clause may not be negative.

Now this was easy enough to understand, and we realized that there was indeed a bug in our query. As we worked to reproduce it in our test environments though, we were startled to discover that reproducing it gave us that fatal error! Upon closer inspection of the production error log, we realized that the OFFSET error had disappeared when we added OPTION RECOMPILE.

This led us to believe that the combination of an invalid OFFSET value in a query using OPTION RECOMPILE causes SQL Server to generate a fatal error instead of a specific & useful message. In other words, there's an error in the error handling code.

We fixed the stored procedure to only use valid OFFSET values, kept the OPTION RECOMPILE, tested, and re-deployed. Thankfully, this eliminated all the errors.

This issue has been reported to Microsoft.

Tuesday, June 28, 2016

The Case for Dealing Directly

Update 8/1/2016: After giving this article some further thought, I added another reason.

Suppose you started a new job, and sat down to look over the codebase. As you dug through things, you found that, instead of using public methods and/or properties on classes, they had written a whole reflection framework to reach into objects and modify the private fields. Then, when you asked why they had done something so very peculiar, they responded by saying, "Oh, this way is much better - we don't have to care about the structure of the objects, or waste time writing accessor methods and properties, and we can spend all our time just writing actual code!"

What? No. What?

We could probably spend a whole series of articles explaining why this is a bad approach, but let's just focus on these reasons:
  1. it works against the language's paradigm
  2. it leads to contrivances that don't use the objects very effectively
  3. it makes figuring out the usage and dependencies of objects very difficult
  4. it has security risks
  5. it is more risky to change
  6. it doesn't scale, and the performance could get pretty bad without a lot of ways to optimize it
This is what dynamic SQL is like, and my reaction to it is the same.

Current or former colleagues of mine might quickly note that I have written my fair share of dynamic SQL, and astute readers might note that I have published dynamic SQL on this very blog before. Dynamic SQL, like reflection, is not a bad thing, and has good uses. But it's generally not good for line-of-business applications, for all the reasons listed above.

Dynamic SQL is code generation. When code generation is employed at design (develop) time, it is a very good thing! Intellisense is the most common form of code generation, and it's so fluent & ubiquitous that we barely even think about it anymore. One of the reasons I sing the praises of ReSharper to anyone and everyone who'll listen (and I'm starting to get there with SQL Prompt) is because of the code generation features. They just make life easier, while still giving you the flexibility to write exactly what you need, because you don't have to accept everything they give you.

But code generation at run-time is a different story. Would you trust an application that generates, compiles, and executes code on the fly? That kind of sounds like the behavior of a virus, or at least the work of someone who doesn't yet realize that they'll have to debug that thing somehow. Sure, it's clever, but it's fraught with security, maintainability, reliability, and performance pitfalls.

There are pieces of code that we have to write that are trivial and repetitive, and that's what code generation is for. But the whole reason programmers haven't all been replaced by robots is that writing good code is not a deterministic activity. It requires a fair amount of specialized knowledge. SQL is no different.

Let's consider each one of these points a little more closely.


It works against the paradigm


In other words, just because we can doesn't mean we should. 

To an application, a database is an external resource, like a file system or an API. Interactions to external resources generally need to be coarse-grained, and resources need to be well-encapsulated. This means that while tables are the basic unit of database storage, they are not the basic unit of database interactions. In an ideal application, any discrete action will incur only one database call - e.g., there's only one call when the page loads, and only one when the user clicks the button to update the page. Relational databases are built very unambiguously on the principle that interactions should be atomic so they can be consistent and isolated.

Dynamic SQL works against this paradigm because it wants to deal with the tables as individual units instead of dealing with endpoints (stored procedures) performing atomic operations. The workaround for this is typically to create a transaction in the application code, which often is a performance anti-pattern - it makes the database layer chatty, and holds locks open longer, which leads to blocking & degraded performance. (There are places where in-code transactions make sense, but they are the exception, not the rule.)

It's true that databases are often under-abstracted and have too much repetition, but the solution isn't to go around the database, it's to employ the mechanisms it does have.


It leads to contrivances


I've never met an ORM framework I really liked (and it turns out there are a lot of other engineers who feel the same way; Google it to find out more). You're constantly having to work around them to get things done properly, and the SQL they generate is almost always a classic example of what not to do in a relational database.

Writing effective and appropriate UPDATE, JOIN and WHERE clauses is not a trivial task. Structuring them in the correct manner requires addressing multiple considerations - the impact to/of indexes, the size of the tables involved, the native change tracking features, replication, etc. Dynamic SQL code generators do not provide any abstraction in this regard: they have to get very detailed in order to provide the level of control needed. In other words, they have to re-create the wheel, and in the end their output is no more optimal, and typically less optimal, than writing the SQL directly in stored procedures.


It makes usage discovery difficult


When dynamic SQL generators build statements, the table, view, column, etc. names are coming from diverse locations, and how they are used is often obfuscated. This makes it hard to know which database objects are actually in use. As with any type of code, when it's difficult to tell what's in use and how it's being used, it's difficult to move forward. It significantly hampers development and debugging efforts. Every database I've ever encountered has had many things in it that everyone is 'pretty sure aren't even used anymore', but because discovering dependencies is difficult even under the best of circumstances, nothing is ever done about it. Dynamic SQL's obfuscation of usage just exacerbates this problem, while direct SQL in stored procedures is much more clear and consolidated.


It has security risks


It is often pointed out that the security concerns of dynamic SQL are mitigated by parameterization. This is true, but it's also true that stored procedures mitigate these risks even further. When the SQL code is being constructed on the fly, it still opens up possibilities for injection (and compile errors) that simply don't exist with stored procedures. (Naturally, stored procedures that build dynamic SQL suffer from these same flaws, and in some ways more so - I include them in the ranks of 'dynamic SQL code generators.' Traitors.)

Stored procedures are also a better way to implement the principle of least privilege. When dynamic and/or inline SQL is involved, the application must be given carte blanche to act on the tables. But with stored procedures, the interactions are much more targeted, and (typically) only one object has to have permissions associated to it. It's more maintainable and granular access, two key elements of good security.

These may seem like minor concerns. They are not. Quite frankly, security in every single piece of software on this planet needs to be better - and not just better, but many orders of magnitude better. Good enough security is not good enough.

It is riskier to change


When every operation is being managed by the same code, the risk of changing that code becomes much greater. If a change is made to a dynamic SQL builder for one scenario, it runs the risk of breaking all the other scenarios - in other words, it is harder to keep changes isolated. Say for example you have code that is generating INSERT statements, and you make a change to accommodate one edge case. In doing so, you run the risk of breaking all the INSERT statements in the application. But with stored procedures, a change to one statement has zero effect on similar statements in other procedures. Changes can be kept isolated, the system is more flexible and we can be more confident in our changes.


It doesn't scale


Typically, the only way to optimize dynamic SQL is to pull it out and make it not dynamic. Yes, indexes are always a part of the optimization equation in a relational database, but they're just one tool, and quite frankly they're usually just the first layer. To really address these matters we have to get into the queries themselves, and when we can't directly control the queries, we're at a serious disadvantage.

Also, compilation is not free. Dynamic/inline SQL execution plans can be cached, and stored procedure execution plans aren't necessarily cached, but the former typically aren't and the latter typically are. It's a significant advantage for the DBAs or the DevOps to be able to look up an execution plan by the procedure name, an impossible task with dynamic and inline SQL. Reducing the number of compilations is also a important step in preventing CPU bottlenecks in SQL Server, something that can only be achieved with stored procedures.


(It is not always possible to use stored procedures - after all, some applications have to interact with databases controlled by third parties. But in these scenarios, inline SQL is preferable to dynamic SQL, because it mitigates or avoids most of these discussed pitfalls of dynamic SQL even though it lacks some of the advantages of stored procedures.)

In the end, this can all be boiled down to one simple idea: deal with the database on its own terms. In that reflection framework example in the first paragraph, the coders are effectively trying to treat their class structure as a set of global variables, or a key-value store. Trying to make something act like something it is not only leads to trouble. Relational databases are fundamentally different from imperative object code, and attempts to treat them like they're not are misguided.