The solution for the problem is very obvious as outlined below, so this is a reflection (a thought) on developer behavior and API friendliness.
Update (Dec-4-2014):
Same with an error message while dealing with NewtonSoft.Json deserialization. This is
Original Post:
This is not a logical bug: a lot of times programmers are not faced with algorithmic challenges. In the code snippet below, there is nothing much to this for loop that add pages from a PdfDocument to another using PDFSharp.
Developers do not scratch their heads to write that piece of code, but sometimes the simplest things take time and effort because developers do not understand how APIs work. We live in a software development world that is filled with APIs whether on the web or local and for most using APIs is a natural part of their jobs which is good until the benefits of using the API e.g. avoid reinventing the wheel and making use of others who studied the object of the API more in depth, are outweighed by the disadvantages: API learning curve as APIs involve learning concepts of the API and a sophisticated object structure, going around things that are not implemented by the API, and so on.
In this particular case, the API that I was using, the PDFSharp library, threw an exception that told exactly what was expected. This is an example of excellent API communication. It told me that I have opened a PDF Document in a mode that did not allow me to import PDFs.
So simply adding PdfDocumentOpenMode.Import solves the issue:
I've had experience with other API that throws the most obscure exceptions even at locations where it is hard to trace where your erroneous API usage originated. Or doesn't even through exceptions but does not do what is required, e.g. doesn't add pages to the main doc so it leaves it up to you to guess what went wrong: the loop was not entered for some reason, reportStreams is empty, the page elements are null, etc?
I can hardly consider fixing such an issue as a programming challenge because APIs are designed by humans, or even if they are "engineered" by humans, there are a lot of things that are just arbitrary regarding how APIs are built. Of course there are choices that makes sense more than others such as naming an API method as GetPurchaseOrders(DateTime, DateTime) rather than GetSome(DateTime, DateTime). The choices increase exponentially from here (Parameter numbers and types, overloads, type structure, complexity, error messages, returning null on failure, empty objects, etc...).
I wonder about the ways to actually "engineer" or systematize the process of "designing" an API?
Update (Dec-4-2014):
Same with an error message while dealing with NewtonSoft.Json deserialization. This is
Message: "Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'ListOfPumpkins' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or ListThis is an actual error message, so much beyond the common COM Exceptions that .NET developers who only deal with managed APIs face which go something like: "COM Exception: 1234, deal with it". This actually shows to what extent the developers of the library care for their follow developers. Once they saw and expected them that they might do something incorrectly and that their code run into an exceptional situation, they communicate it with a good exception like the one above.) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object."
Original Post:
This is not a logical bug: a lot of times programmers are not faced with algorithmic challenges. In the code snippet below, there is nothing much to this for loop that add pages from a PdfDocument to another using PDFSharp.
foreach(var reportStream in reportStreams)
{
var pdfDoc = PdfReader.Open(reportStream);
foreach (PdfPage page in pdfDoc.Pages)
{
majorDoc.Pages.Add(page);
}
}
Developers do not scratch their heads to write that piece of code, but sometimes the simplest things take time and effort because developers do not understand how APIs work. We live in a software development world that is filled with APIs whether on the web or local and for most using APIs is a natural part of their jobs which is good until the benefits of using the API e.g. avoid reinventing the wheel and making use of others who studied the object of the API more in depth, are outweighed by the disadvantages: API learning curve as APIs involve learning concepts of the API and a sophisticated object structure, going around things that are not implemented by the API, and so on.
In this particular case, the API that I was using, the PDFSharp library, threw an exception that told exactly what was expected. This is an example of excellent API communication. It told me that I have opened a PDF Document in a mode that did not allow me to import PDFs.
So simply adding PdfDocumentOpenMode.Import solves the issue:
foreach(var reportStream in reportStreams)
{
var pdfDoc = PdfReader.Open(reportStream, PdfDocumentOpenMode.Import);
foreach (PdfPage page in pdfDoc.Pages)
{
majorDoc.Pages.Add(page);
}
}
I've had experience with other API that throws the most obscure exceptions even at locations where it is hard to trace where your erroneous API usage originated. Or doesn't even through exceptions but does not do what is required, e.g. doesn't add pages to the main doc so it leaves it up to you to guess what went wrong: the loop was not entered for some reason, reportStreams is empty, the page elements are null, etc?
I can hardly consider fixing such an issue as a programming challenge because APIs are designed by humans, or even if they are "engineered" by humans, there are a lot of things that are just arbitrary regarding how APIs are built. Of course there are choices that makes sense more than others such as naming an API method as GetPurchaseOrders(DateTime, DateTime) rather than GetSome(DateTime, DateTime). The choices increase exponentially from here (Parameter numbers and types, overloads, type structure, complexity, error messages, returning null on failure, empty objects, etc...).
I wonder about the ways to actually "engineer" or systematize the process of "designing" an API?