Swagger error 500 when you have a Get without arguments in ASP .NET Core

In an ASP .NET Core project where Swagger was configured using Swashbuckle.AspNetCore package to automatically expose endpoint documentation, I had seen this strange behavior regarding HttpGet methods in controller classes:

  • With a Get method that required an argument, Swagger UI (documentation) was working (properly displayed) corectly.
  • As soon as the Get method’s signature was changed to not require an argument (even as there was no other Get method to generate confusion), documentation was not displayed anymore, and instead an error line like this was presented:
    500 : http://localhost:.../swagger/v1/swagger.json

After digging a lot, I’ve found out that the problem was that under the controller class the routing was established with an attribute – [Route(“api/v{version:apiVersion}/[controller]”)] – while a default routing was also defined in the Startup class (under ConfigureServices method):

services.AddMvc(m => { m.Conventions.Add(new DefaultRoutePrefixConvention()); });

As soon as this line in Startup was simplified, Swagger UI started to work properly again (and moreover, non-versioned duplicate endpoint documentation was removed – another good thing):

services.AddMvc();
Advertisements
Posted in ASP .NET | Tagged , , , , , | Leave a comment

Swift events

Swift does not have built-in .NET-like events. (I admit, I was used to have them in C#, although implementing the weak pattern in .NET was not the easiest job either.) Instead, in Swift there are two common patterns that developers (and even Apple) use for notifications: delegation and completion handlers.

Delegation involves defining a protocol that is separated from the service class, by convention having “Delegate” name suffix. That protocol would include function declarations for (usually) all notification types that the service object can send to a client. The service needs to hold a delegate reference to be able to call it whenever needed, and in Swift that can be easily set as weak to avoid memory leaks. But if we want to hold an array of delegate references instead of a single one, we just cannot set them as weak because the built-in array type of Swift is a value type (which – by the way – has many advantages in other development areas) and the actual item references are out of our control. In such case, we are forced to write a wrapper type over the delegate reference (to be able to mark it as weak).

At first thought, working with completion handlers (callbacks) instead of delegates seems a good replacement, overcoming some of the issues indicated above. While this would indeed work well for adding and notifying subscribers for each type of notification that we need to support, the first problem with this approach is that we cannot unsubscribe callbacks upon request. Simply because Swift just doesn’t let we compare function references (although functions are reference types) due to internal optimizations that the compiler relies on, so we cannot determine which reference need to be removed from the array of callback references that the service would host. Moreover, we cannot easily overcome memory management issues using weak references because function types are special and one cannot mark a function reference as weak, so to be able to resolve this I guess we would need a wrapper over a weak reference to an object that would have a function reference – and in my opinion that’s too much wrapping!

These being said, what can we then do if we just want to have N objects notifying M observers with memory leak protection (besides allowing manual unsubscribing), and – as a personal requirement – to avoid over-architecturing and increase customizability as much as possible, while (of course) trying to also limit the boilerplate code that would need repeated for each event type to a reasonable amount? (I’ve already seen some generic implementations, but for now I just feel that we could be OK without them.)

I think that we can do it this way (for each service that we develop):

  • Define one (or more) Delegate protocols, defining (and optionally further grouping) functions to represent the supported notification types;
  • To be able to listen to many service instances from a common client, one argument of each delegate function should be a reference to the sender service itself (I suggest always the first);
  • Define add- and remove*Delegate pairs of functions under the service definition (one pair for each Delegate protocol) for clients to be able to subscribe and unsubscribe themselves from the service’s delegate lists;
  • Define private wrapper type(s) over delegate object references marked as weak (one for each Delegate protocol); host and manage array(s) of such wrappers and call their references’ functions whenever notifications are to be sent to subscribers.

Easier said than done? Nah. Below there is a complete example that I play with. We have:

  • a service class (with an extracted protocol) that allows:
    • executing operations:
      • doing something;
      • doing something else;
    • adding and removing associated delegates of these types (separated protocols):
      • main service delegate that allows clients to be notified when:
        • something is about to be done, accepting cancelation orders;
        • something was done;
      • secondary service delegate that allows clients to be notified when:
        • something else was done;
  • a client class that:
    • declares itself both as a main delegate and as a secondary delegate for the service class;
    • subscribes to multiple service instances at initialization time;
    • gets notified whenever, at the level of any of its associated service instances:
      • something is about to be done, sending cancelation orders when needed;
      • something was done;
      • something else was done;
    • supports unsubscribing from any of its associated services upon request;
  • main code that:
    • initializes a few services and clients that subscribe to them;
    • calls doing something and something else on specific services;
    • unsubscribes clients from selected services;
  • and: all code includes print calls to indicate what actually happens when it’s run.

Feel free to try it yourself if you wish, either in xCode as a playground, or – why not – under an online Swift playground service, such as this one (although it seems it’s going to be deprecated):

protocol ServiceObject : class {
    var name: String { get }
    
    func doSomething(_ argument: String)
    func doSomethingElse(_ argument: String)
    
    func addDelegate(_ delegate: ServiceDelegate)
    func removeDelegate(_ delegate: ServiceDelegate)
    
    func addSecondaryDelegate(_ delegate: ServiceSecondaryDelegate)
    func removeSecondaryDelegate(_ delegate: ServiceSecondaryDelegate)
}

protocol ServiceDelegate : class {
    func somethingWillBeDone(_ object: ServiceObject, _ information: String) -> Bool
    func somethingWasDone(_ object: ServiceObject, _ information: String)
}

protocol ServiceSecondaryDelegate : class {
    func somethingElseWasDone(_ object: ServiceObject, _ information: String)
}

class Service : ServiceObject {
    let name: String
    
    init(_ name: String) {
        self.name = name
        
        print("Service", name, "initialized")
    }
    
    func doSomething(_ argument: String) {
        let information = argument
        if somethingWillBeDone(information) {
            print("Doing something about", argument, "on service", name)
            somethingWasDone(information)
        }
    }
    func doSomethingElse(_ argument: String) {
        let information = argument
        print("Doing something else about", argument, "on service", name)
        somethingElseWasDone(information)
    }
    
    func addDelegate(_ newDelegate: ServiceDelegate) {
        delegates.append(Delegate(object: newDelegate))
    }
    func removeDelegate(_ oldDelegate: ServiceDelegate) {
        if let index = delegates.index(where: { delegate in delegate.object === oldDelegate }) {
            delegates.remove(at: index)
        }
    }
    private var delegates: [Delegate] = []
    private struct Delegate {
        weak var object: ServiceDelegate?
    }
    private func somethingWillBeDone(_ information: String) -> Bool {
        for delegate in delegates {
            if !(delegate.object?.somethingWillBeDone(self, information) ?? true) {
                return false
            }
        }
        return true
    }
    private func somethingWasDone(_ information: String) {
        for delegate in delegates {
            delegate.object?.somethingWasDone(self, information)
        }
    }
    
    func addSecondaryDelegate(_ newDelegate: ServiceSecondaryDelegate) {
        secondaryDelegates.append(SecondaryDelegate(object: newDelegate))
    }
    func removeSecondaryDelegate(_ oldDelegate: ServiceSecondaryDelegate) {
        if let index = secondaryDelegates.index(where: { delegate in delegate.object === oldDelegate }) {
            secondaryDelegates.remove(at: index)
        }
    }
    private var secondaryDelegates: [SecondaryDelegate] = []
    private struct SecondaryDelegate {
        weak var object: ServiceSecondaryDelegate?
    }
    private func somethingElseWasDone(_ information: String) {
        for delegate in secondaryDelegates {
            delegate.object?.somethingElseWasDone(self, information)
        }
    }
    
    deinit {
        print("Deinitializing service", name)
    }
}

class Client: ServiceDelegate, ServiceSecondaryDelegate {
    let name: String
    let services: [ServiceObject]
    
    init(_ name: String, subscribeTo services: [ServiceObject]) {
        self.name = name
        self.services = services
        
        print("Client", name, "initialized")
        for service in services {
            print("Client", name, "subscribes to service", service.name)
            service.addDelegate(self)
            service.addSecondaryDelegate(self)
        }
    }
    
    func somethingWillBeDone(_ service: ServiceObject, _ information: String) -> Bool {
        print("Client", name, "observes that something about", information, "will be done on service", service.name)
        return information != "canceled"
    }
    func somethingWasDone(_ service: ServiceObject, _ information: String) {
        print("Client", name, "observes that something about", information, "was done on service", service.name)
    }
    func somethingElseWasDone(_ service: ServiceObject, _ information: String) {
        print("Client", name, "observes that something else about", information, "was done on service", service.name)
    }
    
    func unsubscribe(from service: ServiceObject) {
        print("Client", name, "unsubscribes from service", service.name)
        service.removeDelegate(self)
        service.removeSecondaryDelegate(self)
    }
    
    deinit {
        print("Deinitializing client", name)
    }
}

func run() {
    let serviceS = Service("S")
    let serviceT = Service("T")
    let clientC = Client("C", subscribeTo: [ serviceS, serviceT ])
    let clientD = Client("D", subscribeTo: [ serviceT ])
    
    serviceS.doSomething("s1")
    serviceT.doSomething("t1")
    serviceS.doSomething("canceled")
    serviceT.doSomethingElse("et1")
    clientC.unsubscribe(from: serviceT)
    
    serviceS.doSomething("s2")
    serviceT.doSomething("t2")
    serviceT.doSomethingElse("et2")
    clientD.unsubscribe(from: serviceT)
}

run()

Enjoy! And for reference purposes, the console output upon running the code should be:

Service S initialized
Service T initialized
Client C initialized
Client C subscribes to service S
Client C subscribes to service T
Client D initialized
Client D subscribes to service T
Client C observes that something about s1 will be done on service S
Doing something about s1 on service S
Client C observes that something about s1 was done on service S
Client C observes that something about t1 will be done on service T
Client D observes that something about t1 will be done on service T
Doing something about t1 on service T
Client C observes that something about t1 was done on service T
Client D observes that something about t1 was done on service T
Client C observes that something about canceled will be done on service S
Doing something else about et1 on service T
Client C observes that something else about et1 was done on service T
Client D observes that something else about et1 was done on service T
Client C unsubscribes from service T
Client C observes that something about s2 will be done on service S
Doing something about s2 on service S
Client C observes that something about s2 was done on service S
Client D observes that something about t2 will be done on service T
Doing something about t2 on service T
Client D observes that something about t2 was done on service T
Doing something else about et2 on service T
Client D observes that something else about et2 was done on service T
Client D unsubscribes from service T
Deinitializing client D
Deinitializing client C
Deinitializing service T
Deinitializing service S

Note that in this example the clients do not access the service except by adding and removing themselves as event subscribers, and instead it’s the main code that calls the service operations (just for the code to be easier to understand) but in practice clients can (and often will) call the services themselves; just that usually other clients will listen.

Another thing that you may have spotted is that I don’t clean up weak reference wrapper collections upon calling the delegates from within the service class, nor upon subscribing or unsubscribing delegates in the neighbourhood: I just let those nils in as I think the performance would (most of the time) be better this way and that the code is also more elegant – and shorter – without the repeated filtering that would be otherwise needed.

Finally, I just want to add that the (verbose) approach for multi-casting events that I proposed above for Swift can actually be implemented, following the same concept line, with virtually any other modern programming language and/or on multiple platforms, even when they do have built-in events, like C# and .NET do. Doing so would improve customizability on raising those events, and furthermore it would help avoiding memory leaks, assuming that the language is similar and that it offers a handy weak keyword or that the target platform or framework provides a public WeakReference class that does what we want – for C#, for example, see also this.

(Actually, this platform agnosticism itself is an important reason leading me towards selecting a simple, yet verbose solution vs. a more complex, generic event framework.)

And if you just have more simple situations – like 1-N, N-1, or 1-1 observable-observer pairs, you can just adapt some of the aspects of the code above (such as defining a single notification delegate per service, a single weak delegate reference instead of an array of weak reference wrappers, and/or removing the sender service argument within notification calls), accordingly.

Posted in Swift | Tagged , , , , , | Leave a comment

When optionals are… required

Assume you have developed a service, with methods requiring arguments, properly extracted into a interface. Then you (or your customers) would write nice clients for your service. Of course, such clients will probably be unit tested in isolation, such as using a generic framework like Moq. (Even if you have forgot to unit test yours!)

This small example – not very useful itself – illustrates the above:

public interface INumberWriter
{
  void WriteNumbers(int a, int b);
}

public class NumberWriter : INumberWriter
{
  public void WriteNumbers(int a, int b)
  {
    Console.WriteLine($"{a}, {b}");
  }
}

public class SubsequentNumberWriter
{
  private readonly INumberWriter writer;

  public SubsequentNumberWriter(INumberWriter writer)
  {
    this.writer = writer;
  }

  public void WriteSubsequentNumbers(int x)
  {
    writer.WriteNumbers(x, x + 1);
  }
}

class Program
{
  static void Main(string[] args)
  {
    var subsequentNumberWriter = 
      new SubsequentNumberWriter(new NumberWriter());
    subsequentNumberWriter.WriteSubsequentNumbers(1);
  }
}

As you can see, the client class was furthermore aggregated to an instance of your service by a main program (or better, dependency injected automatically).

What great software! The output is “1, 2“, as you would expect. And here is a simple verifying unit test for the beautiful SubsequentNumberWriter class too:

[TestMethod]
public void WriteSubsequentNumbers_For1_CallsServiceWith1And2()
{
  // Arrange
  var numberWriterMock = new Mock<INumberWriter>();
  numberWriterMock.Setup(m => 
    m.WriteNumbers(It.IsAny<int>(), It.IsAny<int>()));

  var subsequentNumberWriter = 
    new SubsequentNumberWriter(numberWriterMock.Object);

  // Act
  subsequentNumberWriter.WriteSubsequentNumbers(1);

  // Assert
  numberWriterMock.Verify(m => m.WriteNumbers(1, 2));
}

Now what? You’re right! It’s time for the next service improvement: it would be so nice if its clients could optionally indicate one more argument when they call WriteNumbers, as three numbers look so much better than only two, ain’t it? (Bear with me, don’t let you mind go to arrays for the purpose of the discussion.)

You adapt NumberWriter class and INumberWriter interface accordingly, considering that this way any existing clients, such as SubsequentNumbersWriter, won’t need any changes in order to continue to be built and run successfully:

public interface INumberWriter
{
  void WriteNumbers(int a, int b, int? c = null);
}

public class NumberWriter : INumberWriter
{
  public void WriteNumbers(int a, int b, int? c = null)
  {
    Console.Write($"{a}, {b}");
    if (c != null)
      Console.Write($", {c}");
    Console.WriteLine();
  }
}

Indeed, when you compile and run the client class and the main program that uses it, everything is fine. But – since I wrote this article – you surely suspect (and you are correct) that the change wasn’t as harmless as it looked like at first.

A problem appears if you’d try to compile… the unit test project. Specifically, you’d get:
Error CS0854 – An expression tree may not contain a call or invocation that uses optional arguments.

What’s the problem? You know it now: Moq framework is nice, but because it uses expressions to define setups and verifications (e.g. m =>
m.WriteNumbers(It.IsAny<int>(), It.IsAny<int>())), it doesn’t support optional arguments.

Instead, to make it work, you’ll be forced to update the unit test and indicate the third argument there, even if you do not care about it in the client class that is tested:

numberWriterMock.Setup(m => 
  m.WriteNumbers(It.IsAny<int>(), It.IsAny<int>(),
                 It.IsAny<int?>()));
// ...
numberWriterMock.Verify(m => 
  m.WriteNumbers(1, 2,
                 It.IsAny<int?>()));

Side note: here you may run into two other issues or questions (a little off topic, but I want to mention them because they are common):

  1. If you enter by mistake it is any int instead of it is any nullable int on the Setup call, the unit test will compile but the verify call will never succeed. And it’s going to be very frustrating as it will be very hard to detect why!
    • Mind that question mark, it’s very, very important!
  2. Should you use it is any in the verification call as well? Shouldn’t you verify passing of null? I believe not, myself, because you don’t test the core service here, but the client class, isn’t it?
    • Indeed, if the service implementation had a different default value for the optional argument, such as int? c = -1, while the interface would still have it set as int? c = null, the mock of the service would receive null, and the verify (with -1 in that case) would certainly fail. You can try it and see for yourself!

Now back to our main case: what’s the conclusion, one might ask.

Well, in my opinion, it’s just that it’s not a good decision to use optional arguments when you extend your services in subsequent version, i.e. adding arguments with default values to existing methods. At least not without considering this as a breaking change, like you would when you’d remove an argument from such a method instead.

(Note that although client unit testing with mocking is a great example of this issue appearing in practice, actually any expression using the method call would break similarly, and probably it will happen in way more important client code.)

What can you do instead? Surprise: plain old method overloading and a bit of code refactoring would turn out to be enough! Moreover, you can still use optional arguments – but only in private methods and maybe in the first version of an API; in public method updates, optionals should never be an option! 🙂

For our example, I’d suggest doing something like this:

public interface INumberWriter
{
  void WriteNumbers(int a, int b);
  void WriteNumbers(int a, int b, int c);
}

public class NumberWriter : INumberWriter
{
  public void WriteNumbers(int a, int b)
  {
    WriteNumbersCore(a, b);
  }
  public void WriteNumbers(int a, int b, int c)
  {
    WriteNumbersCore(a, b, c);
  }
  private static void WriteNumbersCore(int a, int b, int? c = null)
  {
    Console.Write($"{a}, {b}");
    if (c != null)
      Console.Write($", {c}");
    Console.WriteLine();
   }
 }

With this code updates, both the original client class and its unit test will compile successfully, and also will continue to pass. And your change is not going to be breaking anymore: the optionals shouldn’t ever be… required!

(Please excuse my ifs within WriteNumbers method bodies, and any other ugly C# that I didn’t care about. I’m sure you can refactor everything yourself.)

Posted in C# | Tagged , , , | Leave a comment

On onion (cone?) architecture

High level modules should not depend on low level modules. Both should depend on abstractions.

The first three circles starting with the central Domain define the application core. Each of these is a collection of high level modules.

The outer-most blue circle is about the details. This is where everything that’s less important goes. This includes all the tools, frameworks and models that support the application core. […]

The green circle is the glue that connects the application core to the details that support it. Adapters are user code implementations that are specific to various details in the blue circle and that hide these away from the inner core circles.

[You define adapters in the green circle, reusing technology details in your blue circle and calling Presentation service from the inner yellow circle. But what if your app also needs to use a delivery framework detail?]

Every piece of code in the core that needs some external service defines an abstraction for that service. […] This abstraction is called a port.

Later, an adapter for the port is defined in the green circle […]. [It] implements the core abstraction and forwards the calls to the specific technology in the blue circle.

via Cone Architecture — Adrian Bontea


I’d still call this “onion architecture” as I think it must remain very clear that the core is to be hosted inside of any executable package, but the points of the linked article are all valid. And indeed, from my point of view too, core reusability is a must for all successful software projects – since their very first version, or even their PoC.

Of course, following the dependency inversion principles in real projects is really difficult. Both because many times it’s not intuitive (especially if you are really tech-focused and you know very well what certain contemporary technologies can and cannot do and you are eager to use one or another to implement what you need) and because you could often end up with thick (or very thick) adapters, for which you’ll need to trade off their implementation cost and the benefits of better core reusability.

The first issue is usually resolved by just sitting down with a pen and a piece of paper and thinking deeply while you draw your diagrams.

For the second, the things are more difficult because many times this would seem to increase costs. But do note that reusability is implicitly required if you’d have a long term, successful project because technologies – i.e. details – will change over time outside of your team’s control. And you don’t want your project to become legacy too early, as the cost of continuing to maintain it into the “new world” would have become too high. (Think about the recent rise of the cloud, mobile devices, and maybe that of the 3D holography in the future, and about the applications that you needed or you’ll need to rewrite from scratch to ensure they’ll live on.)

Moreover, if you do multi-platform (rather than cross-platform) development, reusing the core concepts (i.e. they might need rewiring in multiple different core programming language) is a must from the beginning. (Think about having to write the same logic in C#, JavaScript, Swift, and Kotlin; having the core domain, application, and some generic presentation services extracted – maybe with pseudo code and some agnostic modeling tools – makes all these conversions a lot easier.)

Finally, it’s OK if you’ll also get multiple other partial onions within some services, such as presentation or adapters. (For example, if your main domain includes a hierarchy of objects, and your presentation services expose visibility values for items based on expansion/collapsing parent items, that part may be extracted out into yet another separate domain that is unrelated to the main one: a domain of tree nodes with expansion state, and items with computed visibility under them, reused by main presentation servies for preparing the main domain hierarchy for user output, and does this in a generic fashion, that later can be further adapted to 2D screens, large or small, read by Alexa devices, or exposed in a 3D diagram.)

Or maybe you’d want to also remove the dependencies between the core services themselves – i.e. having the application and generic presentation services totally disconnected, using an app controller that would just manage the required interactions and orchestrating everything (acting as more than adapters), and overall you’d still benefit of the same dependency inversion idea that brings life to the onion concept (or be it cone, if you wish, to get better mnemonics, as Adi advocates?)

Posted in Architecture | Tagged , , | 3 Comments

Computers return

In the recent years we’ve all seen that the computer market was going down badly, while the smartphones increased tremendously.

But checking GlobalStats’ OS market shares today I found a big surprise (is it a Christmas present?): both Windows and macOS are now doing a lot better than just a few months ago. Windows overpassed Android again, while macOS broke the 6% percent share the first time after its 2015 fall (that – for people living in the north hemisphere – actually occurred in the summer), maybe helped also by iOS remaining at around 12%.

What happened, one may ask? This video explains it very well: the previous rumours suggesting that we’ve entered a “mobile-only era” (that I’ve wrote about myself a few times) have turned into a real fact with an important difference: it seems we’ve entered the “mobile+computer era” instead.

The recent PC and Mac sale issues may have therefore been caused just by the smartphone hype and implicit fear that such small devices could eventually replace large screens completely. That was somehow illogical, indeed, at least for businesses – my wife kept warning me about this – but many of us (included myself) started to believe it could happen; since markets – on such a long term like two or more years – weren’t expected to lie. (Probably they actually didn’t, and one just needed more experience to understand them while things went up and down, creating false trends which may have looked – at specific times – unbreakable.)

So, what does this mean for us, programmers? I guess we should still learn Android and iOS development (if we aren’t there yet) as the mobile duopoly is here to stay and computers’ return is not going to make smartphones disappear. But at the same time, we can now (more) safely restore some focus on our Windows (and macOS!) desktop applications as it seems they will continue to bring us good revenue in the future too, while – of course – we can keep an eye on the monthly GlobalStats as well, just in case.

Posted in Miscellaneous | Tagged , , , , , , , | Leave a comment

macOS milestone

As a Windows app programmer that wants to also develop native iOS and Android apps, one should learn to develop native macOS apps first! In my opinion it’s easier to learn standard Cocoa first, and only then Cocoa Touch (sharing, of course, the Foundation and other concepts). Mostly because on a Mac you have more power, a large screen, and – even more important – a mouse, just like it was on Windows before!

With macOS supported, one would have already learned a lot about Apple‘s development tools, including the Swift language, the core types and all commonly available features.

Finally, despite its market share, and considering all (other) economical reasons as well, I think you can safely let Android the last: even if simply because Apple‘s ecosystem has a desktop operating system that is raising in market share – becoming a valuable milestone towards the mobile duopoly and being highly similar to what you’ve been used to – while Google‘s Chrome OS (although raising too recently, and interestingly starting to support certain Android apps as well) is generally more (i.e. too) close to the Web.

Moreover, by retargeting your Windows apps to the Mac first, i.e. before getting them rewritten for the mobile devices (and lastly, for Chromebooks), you could get some earlier profits: Mac users (even more than iPhone owners) are – from what I saw around – people that understand very well that good software cannot be free and they will be happy to pay the correct price to obtain it.

Introduction to the above

Until recently, Windows was everything to many developers. Java and Web struggled to become the next big things, but in my opinion they both failed to become dream cross-platform technologies.

During the years, many of us have therefore become Windows and eventually .NET developers, probably embracing C++, Visual Basic, then C# programming language and Windows Forms, then WPF for user interface development. And we’ve learned Java, JavaScript (or TypeScript) and frameworks on top of them only if it was really needed. (While for Web on Windows we had Silverlight and WPF browser apps, remember?)

In the meantime, as mobile devices become more and more popular, we were all hoping that Microsoft will eventually come up with a successful strategy to get signifiant market share for their Universal Windows Platform concept in that field, especially as they were abstracting virtually everything really nice, from the operating system to user interface development. If we could have continued living that dream, WindowsC# and XAML could have remained all we’d needed (unless we just wanted to learn more for fun).

But as all Windows mobile strategies failed, and have seen Apple‘s iOS and Google-backed Android breaking all records, we needed to ask ourselves: do we want to continue with the .NET technology-oriented development only? If we answered yes, we could thank Microsoft for acquiring and freeing up Xamarin, but hey, cross-platform frameworks always have drawbacks (just like Java and Web browsers) and we just don’t like that.

The correct answer, in my opinion, was in fact no: we didn’t need to remain tied up to Microsoft while it seemed their big ship was sinking and while just some cloud services business could be saved (using emergency boats). Instead, we could embrace Apple and Google client technologies too, actually just like Microsoft themselves seem to do now!

And assuming that we’ve selected the multi-native platform way to go, we just needed to decide what to learn first: iOS or Android? And that last question could have only one right answer too, I guess: none of the above. macOS should be first if we have previously been developing Windows desktop apps, as I explained in the first section of this post…

Posted in Development | Tagged , , , , , | Leave a comment

App backend selection

Assuming that we want to develop a simple app – e.g. the Shopping list app example that triggered my previous post – and make it available for multiple platforms (Android, iOS, and also Web to cover other devices including Windows and macOS), how do we develop the backend services nowadays? (As P2P-Web is just a dream, and cloud is all we have?)

One idea is to develop the backend ourselves, and expose it using a REST API. Fairly easy to do with ASP .NET WebAPI and Visual Studio. Even on a Mac. Then host it either on our server or in the cloud.

Yet, better choices must exist – easier to implement and skip both the development complexity and the deployment hustle – ain’t it? Indeed, there are a few good choices out there:

Studying them a bit, I think that personally I would go with Google Firebase if I needed to make a selection today, although it includes fewer cloud products overall. Because of these small reasons:

  • Google offers a small real-time database instance 100% for free and supports multiple platforms, including Android, iOS, the Web (JavaScript), and REST (for example to be used from macOS or Windows apps – although there authentication of users, such as using Facebook or Google might be trickier). Most importantly, however, Firebase provides events when data changes, which saves much development time since you don’t need to re-query the database periodically (unless you are using REST) – data changes come to your code, directly. And it seems possible to easily set up working offline too – a nice extra.
  • Microsoft Azure offers a database for free too, but as I understand this is only for a year, and maybe my app won’t be successful and I would forgot about the subscription and therefore free for life is better. Besides that it offers good features, including data syncing and working offline (with Cosmos DB).
  • AWS does have a Free tier that includes a NoSQL database (DynamoDB) but it seems their pricing system is more complicated in case we’d eventually need to scale up or use other products; moreover, syncing between client app instances and the cloud, change notifications, and working offline don’t seem to be core concerns in their SDKs (although the number of supported platforms is the highest at Amazon.)

But it’s highly possible that I missed something! I admit, I didn’t have much time to do the hypothetical analysis and offers change so often in this cloudy world (today’s picture is highly different than that of two years ago when I last checked.)

Maybe you can help with further suggestions if you have experience with some of these tools: what would you choose, and why?

Posted in Development | Tagged , , , , , | Leave a comment