Azure B2C and Azure SF – Postmortem

For a client of mine we used Azure B2C with custom user flows, and used Azure Service Fabric. Both in a production environment. And we decided to move away from it.

Why this happened is something I am going to cover in this postmortem. I write this blog so others can better decide on when to use these powerful tools and when to refrain from using it.


Azure B2C: a powerful IAM solution. The custom user flows: very specialist tooling, requires in depth specialist knowledge. There is good documentation on it, but very few actual examples. With it missing the nuances of real world scenario’s, it is very hard to learn by just using it.

  • Azure B2C custom user flow documentation is lacking on actual production experiences.
  • Azure B2C custom user flows use a xml configuration approach that are hard to understand, and not that many people are actually using it.
  • Azure B2C is more limited in feature set than Azure AAD. Not problematic, but deceiving.

Service Fabric: a powerful micro-service orchestration tool with optional interesting programming models. Just don’t be fooled by the simplicity of the programming models they provide like the stateful service and actors: there require serious thoughts to be effective, require specific architectures to work properly, and require additional administration to be useful in production environments.

  • Missing documentation on SF actual production experiences.
  • High administrating costs for SF.
  • Increased complexity with SF without being able to reap equally big benefits from it in the short run.
  • Distributed services require their own architectural patterns to be use-able.
  • Moving code to a micro-service architecture is hard to do with small increments.
  • You should have automated a lot before moving to SF: data should be already moving fluently throughout the landscape, services the same.

We were loosing flexibility way too quickly without providing as much benefits as we liked to have. It dawned on us that we had no benefit of Iaas and should look more at PaaS or even SaaS for a lot of the non-core systems we had.

The business case

It started with the client wanting to get a good performing system. We all know a micro-services architecture can help with that, but they are hard to pull off. The promise of SF was to give almost infinite scalability when using the actor pattern, with at the same time providing a programmer friendly solution with the typed data storage and the fluent remoting capabilities, and being blazing fast while doing so.

For their IAM they had this simple request: we need an application specific account to be created when a user does a sign-up, and we want our application specific authorization information on the token. To stay within the Microsoft ecosystem and leverage the power of the cloud, they looked to Azure B2C with custom user flows to provide this. On top of that, the pay-by-call offering of Azure is really competitive with alternative hosted solutions.

Implementing the SF infra

The first step was to move away from the previous solution. For hosting they had Functions Apps, and for IAM they had plain Azure B2C without any user flows.

Spinning up an SF cluster on Azure proved to be simple. They put API-M in front of it with SSL offloading. And their Blazor WebAssembly didn’t even had to look to another endpoint because it was already looking at API-M.

However, API-M’s offering without its downsides. It will add a substantial amount delay to each call, it will only allow 4000 calls/sec per instance, and you don’t get high availability with just 1 instance. Service Fabric does have a loadbalancer build into it, and it does have build in capabilities to negotiate SSL connections without the app needing to bother.

So we decided to move away from API-M and connect directly into the cluster. This brought is to another issue: the build-in SSL wasn’t working. Just didn’t work, and was impossible to point why the certificates didn’t get loaded. No one ever had this problem before (of course) and the issues that were reported are from local development systems not being able to run their local cluster. That shows how many people actually got to use this in production…

Since the SSL is for an application running on machines that can be cleaned in an instance, getting certificates to it manually became the next challenge. We ended up getting the certificate through our own keyvault connection on application start, so we had the certificates available when the connections got instantiated. Custom code on a location where I would rather rely on code from smarter people than me…

Another issue we ran into early was the size of the VM needed to run SF on. By default, SF isn’t configured correctly so it blows up, uses all available space, and services just stop working. Really really not cool, Microsoft! Yes they say you need to run on bigger instances by default, but the problem is that the default configuration will need 100GB at least, and still can run into issues. The cleaning up just isn’t configured correctly. VM’s with more that 100GB are very expensive, even for a test environment, and you need at least 3 to create a cluster.

Moving on to another issue we ran into early: quorum loss. SF runs a raid setup of its services and your application. But you need to make sure SF keeps its quorum, even more than your application. While 3 can survive the loss of 1, there is a lot of things that happen automatically on the background that can cause at least 1 VM to be unavailable and if this coincides with another issue, your whole cluster is destroyed. We learned this the hard way. You need to have 5 machines at least if you don’t want to rebuild your cluster once in a while. And even that is tight.

Another thing you want to do is make sure SF knows early that your application is down. It uses health probes to know the health of its nodes, and it can use this information to decide on delaying impactful actions like upgrading a VM, moving your application to a new version, or while moving to a new version sense that something is wrong with the new deployment. There are 3 ways to get a message to SF: on startup of your application, just throw an exception and exit the application if you think the code can’t run well -> SF will push this to the event source where it listens. Another way is to get an event source message with the failure to SF manually within the grace period of an upgrade. And the last one is providing an http endpoint where the loadbalancer can look at to decide if your application is healthy enough to receive load or where the VM group can look at when deciding to do maintenance on 1 of the machines.

This moves us to reporting on the health of SF and your application(s). Another point of concerns. Every dependency that can impact the state of your application needs to be visible. With SF, you are responsible for the fluent working of a lot of components. That isn’t immediately clear when you first look at the offering. And thinking ‘it will probably run o.k. out of the box’ is a very naive approach: it won’t and it can’t. So to have a good understanding of the health of an application on SF, you need to: know if the application is running well, if all partitions are running well, if all standby nodes are running well, if the SF infra is running well, if the machine is running well, if other infra components (like the load balancer) are running well. Getting these metrics out of all these systems uniformly, get them on a dashboard, merge them with your application state… and then keeping them healthy. That is an administrative task that requires a whole different skillset than the original ‘just add SF with Actors and it scales’ promise!

And now the hottest subject, the one that killed our application countless times. Migrations. You see, stateful services are a combination of data with code. And while upgrading, you essentially run 2 different typed versions on the same data at the same time. This tight coupling of data and type gets really problematic. My personal believe is that to migrate you should not change your data format, but move over to a new version of the service instead. And then somehow get the data over to the new service, or let the old data live in the old service and use an intermediate service like a librarian to point to the right data. This is very costly to implement, I know. But this is how you should think if you go distributed-micro-service-always-available. The alternative to this is nightly migrations, with a lot of orchestration and tooling needed.

And while were are at it: the tooling on SF is very limited. My personal experience is that you want to write your own administrative interfaces as soon as possible. The documents are in a limbo on the powershell, moving away from an old version, the SF api calls are very difficult to manually operate. But you need to have these tools ready to quickly respond to situations.

A specific tool that is not that as useful as you think it is, is the backup service provided by SF. It is meant for returning to a point in time, not disaster recovery. To put it mildly: it is not usable for a production system. It needs the backup API to browse through the data, manually looking at the data (or manipulating it) is not possible to do without writing your own parser, it stores data per partition, and you need to have knowledge of the old application partitioning setup to properly put things back. Good luck using this tool, even with manual commands, to restore to a new cluster. Don’t rely on this backup with the current toolset to provide for a scenario like that. This backup service might be useful if you are going to invest time in how it works under the hood and build a lot of custom tooling around it, probably with your own database of metadata, so you can better support a few common recovery flows. We didn’t have the time to build these tools, and we didn’t count on needing those. So we had a few incidents that left permanent marks on the reputation of SF being a useful tool out-of-the-box. Especially the ‘business guys’ could not understand that with us having a backup we could still be having (partial) data losses.

Implementing micro-service patterns into SF-enabled code

Aside from SF being infra you need to administrate, programming on it should be a breeze. It provides a lot of interesting patterns with its api’s.

We did start with our application being a CQRS system. There is a lot of potential to upscale a system like that. When we started moving to SF each domain had its own code base, but the API that brought it all together was just 1 solution. So while it looked like a micro-service with DDD like boundaries, it behaved like a monolithic application in practice.

Then the first issue arose: how to change the code to leverage the Actor model? Can we just replace a DDD instance with an Actor?

No. There is this ‘minor’ notion of Actors not performing well if you put a lot of calls to 1 instance, or if you need to do a cross-actor query. So very quickly the Actor model wasn’t looking that good of a fit without changing over the whole code architecture. It works well if you have each user interacting with its own actor on a large scale, but if you have for instance a root DDD object and you put this into an actor you instantly have a bottleneck that can’t be scaled.

But luckily SF provides a more ‘basic’ stateful service. It works a bit like a documentDb but typed. So we implemented this in a service-repository pattern. Easy to start with, easy to understand. A stateful service for each domain. It works like this: the API gets a command that ends up in its own business logic (BL). This BL then calls the appropriate stateful service through remoting. This stateful service then looks in its typed datastores and changes stuff.

However, the nuances of how to use a distributed database are quickly lost if you ‘just implement’ this. For instance, if you create a single partition statefull service, you can do magic in this thing. It is really fast (really really fast), and since you are so close to the data even multi-record spanning queries are very fast and consume very few resources. So yeah, if you have a DDD model and store the instances of your root object there it can handle a lot of load. But with just 1 partition you still are limited to be able to run on 1 machine in SF, so you can only scale up instead of scale out.

But how to run this on multiple partitions? Well, you can’t change this afterwards. Can’t. You see, SF doesn’t know about how your data is partitioned, only you do. So… we basically got f*cked there. We ran in production with this and it runs very well on 1 partition but understood this wasn’t the way forward.

What we should have done instead was implementing a ‘librarian’ that handles the cross partitioning calls and points to the right partition. And have a data migration strategy, to move from one partition strategy to the other fluently with code still running.

A bit on the partitioning of data: if you for instance look at cosmosDb it is easy to give it a partitioning that will net you a few hundred to a few thousand partitions. There is no additional cost with each partition. With SF it works the same, but it runs a few secondary instances for reliability. Still it bundles up stuff per service/partition, but its not that fine grained as you think it would be. You don’t want to manually administrate these partitions or have to restore a backup manually.

Implementing B2C

Luckily the B2C implementation was more easy to do. Actually, it was very easy to get the basics working.

However, problems started with the use of PKCE in our SPA applications. This is the new way to go with OpenId auth flows, but there isn’t that much experience with it yet on the internet, compared to the old ways. And B2C is in the transition to be fully embracing PKCE, with even functionality missing that was possible in the old flow.

For instance, there isn’t the possibility currently for server to server communications with tokens on B2C. Just… not there. We implemented our own API tokens to do so. Not cool Microsoft, not cool!

And back to the issue with our SPA application: getting the Blazor WebAssembly to properly inject endpoint specific tokens for each different endpoint was not trivial. There are no examples of this because it should ‘just work’, however with our setup it didn’t.

Another thing is that the B2C examples are missing an important part: SSO. With the PKCE flow a lot of the duration on cookies and sessions have been shortened for increased security. But we still want our customers to have a not-that-much-interrupted-flow when it comes to sign-up and sign-in. So it took us a lot of going through examples and experiences of others to piece together a working setup. We are using a couple of identity providers, so a lot of code to go through and keep working.

The main reason for using custom user flows was the ability to create accounts on our own application as part of the sign-up flow on B2C. As with the other B2C things, finding good Microsoft documentation was hard, but luckily there are a few people that share experiences of their own and we could piece together a working setup. The hardest part was to understand how to write these user flow steps and why it works this way. I still don’t understand each and every detail but I can change some steps now.

Another thing we wanted to do was having our own data on the tokens so we don’t have to hit the back-end each time. We got this working, it used most of the same things as the sign-up used anyway so we could rely on our previously acquired knowledge here.

But we did eventually move away from this ‘own data on token’ due to architectural reasons: you want to have tokens that are limited to the resource and even only the action itself. We didn’t do this so our token grew too big. And in addition to that, we wanted more control over the lifetime. This is probably possible to pull off using more of the custom user flows, but we really didn’t like the idea going there. Using something like identity server is much better documented and more people how to use a technology like that.

The issues

Here a brief summary of the problems we faced already

  • Missing documentation on SF actual production experiences.
  • High administrating costs for SF.
  • Increased complexity with SF without being able to reap equally big benefits from it in the short run.
  • Distributed services require their own architectural patterns to be use-able.
  • Moving code to a micro-service architecture is hard to do with small increments.
  • You should have automated a lot before moving to SF: data should be already moving fluently throughout the landscape, services the same.
  • Azure B2C custom user flow documentation is lacking on actual production experiences.
  • Azure B2C custom user flows use a xml configuration approach that are hard to understand, and not that many people are actually using it.
  • Azure B2C is more limited in feature set than Azure AAD. Not problematic, but deceiving.

But there is more. If you look at the problems we were facing, there were underlying decisions and assumptions that caused this from being ‘issues’ to being ‘problematic’.

  • Wanting quick performance and scale-ability rewards without spending much effort and time.
  • Keep working with a small team, with easy-to-find expertise.
  • With code: keeping everything typed, use remoting connections for much easier follow of calls throughout the landscape.

We couldn’t just add a lot of administrative tools for SF, that would be against our own principles. Tools like that needs to be maintained and require in-depth knowledge. Same for B2C.

We couldn’t also just add a proper micro-service architecture. It will increase the complexity a lot, making it harder to find suitable people. We needed to keep this in check and use a more simple system.

To sum it up: we didn’t like were this was going. We were loosing flexibility way too quickly without providing as much benefits as we liked to have. It dawned on us that we had no benefit of Iaas and should look more at PaaS or even SaaS for a lot of the non-core systems we had.

Solutions, if we did continue down that road

One way to leverage the power of SF is to instantiate a new application for each customer. For example: if you host events, and you want to host a new event, just spin up a new instance of your application for each event. This way you can much better utilize SF scalability, and even use its VM’s affinity system to have different offerings of performance and availability.

Embrace micro-services. Make each micro-service really able to live on its own, being discovered, consumed, handle its own data. And then have interfaces on this service to allow it to move its data to another micro-service of the same kind but allow for version differences. For instance: if you have an api that needs a store. Discover this store, connect to it, negotiate an interface version, get the data or mutate something, and return to the customer. But when you want to move to a new version, let the old one live, release a new one, and let this new one finds its place. Some data will end up directly on this new service, other data will end up there eventually. The mayor technologies here are the versioning , the discovery and the migration handling. But if you do it like this you can very easily re-partition services, break versions, do rolling upgrades/downgrades, have services work independent of each other.

Get a proper micro-service orchestration tool with integrated SF flows to execute maintenance procedures. And have application specific logic in for the different applications to allow for even finer grained maintenance control, like exploring the typed data, manual fixing stuff, things like that. You probably have to develop this on your own, I couldn’t find it.

And on Azure B2C: just get someone with specialized expertise in Azure B2C. Creating and managing IAM systems is a trade on its own, doing it in Azure B2C is a product specialization.

Our next step

I tried to my best to get SF to run within the constraints my client had in place, but it didn’t work out. Same with Azure B2C.

They concluded 3 things:

  • Use more commonly-used technologies so it is more easy to find expertise for it.
  • We want to keep the complexity low to keep the amount of developers needed low. So use more commonly used patterns to solve our problems, use less custom code and use more readily available technology.
  • Lets get our code to a better scale-able architecture first, and while we are going there decide on the PaaS/SaaS components we want to use.

For you

If you are still on SF or Azure B2C, here are some helpful things I did find while working with it.

Service Fabric

A troubleshooting guide for most SF problems

If you want to edit some SF properties but the interface isn’t allowing you to do so, you have to use powershell. But there is an alternative: Especially useful for editing ‘fabricSettings’:
Select your subscription -> resourceGroups -> “your SF cluster resource group” -> “cluster name” -> providers -> Microsoft.ServiceFabric -> clusters -> “cluster name”
Don’t forget to change to ‘Read/Write’ and then use the ‘Edit’ button.
If you don’t see the edit button you browsing went wrong somewhere. There are multiple views of your cluster data that can be very deceiving!
And try it out on a test server first! If you push your data the upgrade will start immediately, depending on your cluster being bronze/silver/gold/platinum the cluster is more graceful in keeping things running. Unless you break something of course, so back up the json before you alter it!

If you need powershell, you do need the Azure powershell one. This is their new way of doing things. For that, head over to The documentation of SF is a bit all-over-the-place. There is normal powershell with SF powershell commands, Azure powershell with Azure specific commands, and you can use the SF rest api by using powershell. Just know these are all different. And some calls are deprecated, some are replaced, and some don’t have a replacement so yeah… thanks Microsoft?

On getting the backup to work, I used these resources.
A note on using the backup restore in the Explorer: I ended up using the SF rest api to restore, this one I could get working reliably. I could not get the Explorer to work here.

Azure B2C

Basic setup

Interesting blog with a lot of real world examples

Some insights into session behavior

If you want to integrate an API of your own in Azure B2C, this is the documentation for that piece

CI / CD in practice

In this blog I want to take you, the reader, with me on my quest on finding a comprehensive CI / CD practice for a moderate to big corporate environment. I personally think efficiency is reached when your practices relate to other processes in the organisation. So In this blog, it isn’t that much about tooling but more of the interconnections between the tooling and the practice.

The tools

As you might know I am a Microsoft developer, so the tool of choice is Azure DevOps. I implement apps and api’s, so add Azure, Xamarin and to the list of tools too.

My development process of choice is a ‘real’ Agile environment using Scrum, DevOps and Google design sprints. Agile is all about team trust and team responsibilities. Good CI/CD is very difficult if the team isn’t trusted with the task at hand.

The pipe

Basic strategy

Everything that get’s build/produced is under code control. So when I say ‘code’ it could be all kinds of development work, not limited to programming apps/api’s.

We work on master alone. And only (automated) pull requests gets merged to master (CI).

The pull request is part of our Scrum Definition of Done, and thus gated with a review and a 2-pair eyes policy. Plus additional checks incorporated into the build like unittests and SonarQube analysis.

In the CD pipe we always incorporates an automated test step, in short AT. Postman for .Net (Core) API’s, Xamarin SpecFlow UI testing for apps, Protractor tests for Angular web apps.

There are different CI/CD builds pairs for different components in the landscape. We strive to have a 1 on 1 relation between a build definition and a component. But there could be a couple of codebases in one repository, especially with the ‘start small, specialize later’ approach most of our projects take.

If we use components, we want to use as much ‘native’ as possible. If we make components ourselves and they are shared components, we avoid interconnections between products: a change in one component can’t automatically result in a few broken (non build-able) products elsewhere.

Make sure all this stuff is easily automated and easy to maintain.
In my field of work this all leans heavy on mechanisms in Azure DevOps. They do supply a lot of tooling to get these things like triggers and gate policies automated, have integrated components versioning strategies, and all these things actually work out-of-the-box.

But don’t over automate. Seriously. Rigorous gating checks and extensive templating breeds laziness. Agile is about people, and using the right tools for the right jobs. I think the key to working fast isn’t about automating alone but more about a balancing act between doing things yourself and let others do the work for you.


All work starts with the Scrum Sprint. From there on we define stories. These stories get refined, and when planned for sprinting the tasks get defined. The tasks are then used to attach one branch to when there is a need for a code change.

So in practice, each task that has a code change that triggers the whole CD pipeline. So for each part of your code you know the delta in stability because of the rigorous checks that the AT environment will do.

Make sure you know the impact of the business side (features/stories) on your product.
With our practice we know for each task and story how it impacts our total codebase and how well the new code integrates into the old.

I hear some of you thinking: ‘but each merge into master gets released if you do CD’.
Being practical, I know that not all of the code can be released as soon as it seems to work. I think it is perfectly fine to gather work at the A environment and review it during the Sprint Demo, and start release it afterwards. But I want to add to this that this is for functional reasons only, like instructing users, instructing 1st/2nd line support or getting functional approvals from involved parties.


My CI/CD strategy is build on testing: fail fast and fail often.

Early stage checks should be red often, because I believe that you only learn (and grow) through failure. The CI builds should fail the most, the TA environment should gate 99.9% of the others failures. In acceptance, there must be only functional issues that could halt the pipe.

I don’t believe in a dedicated T environment for manual testing that much. All manual tests are to be automated. If you need some testing, or didn’t automate something yet, our A (Acceptance) environment is supposed to be used for manual (but non-intrusive) testing.

A word on special case testing with prepared databases and such: because we actively monitor the functional coverage of early testing like unittests, and combine this with automated integral testing through API and App testing, there is low to no need for prepared manual special case testings.

I do not believe in total coverage of all kinds of tests all the time. The determined coverage should be the outcome of a risk assessment to determine what parts need what kind,width and dept of coverage.

To make sure there is enough coverage, I rely on a very practical rule.
“I always make sure I trust the code that stands ready on the A environment. I even trust it that much that I dare to start a production release and walk away and go home knowing everything works as intended (and have the support phone with me).”
If I don’t pass this challenge, it is time to revise testing decisions.

And a thing on loadtesting. (TLDR: most of the times it is not worth the investment.)
I only use it on special occasions to get directions, we don’t have it automated in our pipe. To me it is just too errorprone. It is hard to analyse the code to get a meaningfull coverage, and very hard to get production like benchmarking (especially with monthly changing consumer demands that have way more impact than code changes). It is also very expensive to do this kind of testing, because you want to run this on production like environments with production loads to have some meaning.
And why all this if we are in control of support, have live production health monitoring, cloud scaling, and a very fast delivery pipe to correct code if something bad happens to the performance due to bugs?


For me monitoring isn’t restricted to the CI/CD pipe. The released product is the most essential part of the CI/CD, because it tells the real story about the state of the product that is in the CI/CD pipe.

So here are some CI/CD metrics. For us the most important is the state of the pipe (is there a bug detected in code) and where is what code change waiting. This is live on display on dashboard.
But I found out that a lot of the management is interested in CI/CD metrics too because they want to feel in control and thus monitor things like failed build ratio’s or defect ratio’s (features released vs production incidents).

Another part in metrics is our Azure monitoring. We monitor live production performance such as latency, throughput and error rates. These are essential values for product support, but also helpful to determine the quality of the code in production (and thus in the CI/CD pipe). It is difficult however to select the right measurements, and even more difficult to define alert thresholds (because you need to know what action to take, and most of the time you just can’t do a thing about it).

And the last but the most important: business metrics.
Because I think value driven development is the best there is, we want to know what the added value is of each Sprint the team makes. We monitor this by analyzing key points in our products and showing the results on a live dashboard. It is hard to get right, and we aren’t nearly there. But right now a lot of the roadmap is decided on input from these metrics.
Back to CI/CD: you want to know the value of your individual released parts. This can only be done by measuring some kind of business value and relating this to changes made in time.

A note on support: Our metric selection is suited for live support of a real product, but only on a business hours (8/5) support contract. There is 3rd party 1st line support, but they don’t have monitoring. So in essence, I strive for pro-active monitoring during business hours and pro-active error support.

My wishlist

Well, as you might guess I still want to add or change a few things.

  • Better measurements on the added value of releases (to the customer / business). Currently our measurements are not consistently implemented, and when implemented it is most of the time in a customer-facing component. We should add a monitor to report API relevance, the added value of an expensive fail fast-fail often pipe, etc.
  • Better reporting to management on how we perform. I want to have metrics/processes that have an eye for the individual team and its struggles, but at the same time raises the bar so you keep improving. (No, no failed integration build metrics… don’t waste your time on that)

The real deal

This is all from a real-life situation: my current work at the NS.

Here the team dictates the CI/CD strategie (so different teams have different strategies). The team also dictates the Scrum process: when to accept work, how to implement, how to release (ship) it, and how to do maintenance.

To facilitate the team (and only facilitate) there is a so called ‘cloud’ team supplying tooling, and there are architects available for consulting. The boundaries supplied by these entities are relatively free: it puts emphasis on the teams responsibility to deliver outstanding work.

The amount of freedom is monitored by all involved parties. Not all development teams receive the same amount of freedom. That’s oke with me, because trust is something you need to earn. And my team has earned it!

Why Agile is not another buzzword

In my daily life I am a senior software engineer, practicing the latest insights on Agile development. I have seen many organisations, small and big, old or brand-new (even startups). Using this insight I can spot a lot of problems with the often contradictory methods of development organisations are using to create software.

First a quick introduction to Agile development. Because it is often used as a buzzword with few meaning left in it. Non-agile is the factory line: in advance you plan and rule out all odds, the actual work is thus repetitive and not requiring a lot of skills (although you can argue it can still require some practice… but that’s exactly the problem: no thinking involved). It is input driven: someone somewhere decides what has to happen, everything and everyone falls in line to execute on that. Everyone has a predetermined place and function. You don’t need trust, you need rules.

Agile is the opposite. When you are agile you think of what you want to achieve, and make that happen with respect to the current state of the world and the tools at hand. By building on trust, by being in connection with everyone, by embracing the unknown. Yes that sounds idyllic, because that’s how humans like to be.

But why all this Agile or non-Agile? Why bother with project methodologies anyway? Just build something already!
Well, the following picture illustrates how a perfect world would look like. Look at all those connections. It would be great if we would build products in a world where all those connections between the content creators and consumers were flawless.

This image has an empty alt attribute; its file name is agile-gaming-perfect-world.png

However as you probably know from your own experience, all connections between humans suffer from communication issues. This is the same picture, but now with the possible issues.

This image has an empty alt attribute; its file name is agile-gaming-our-world.png

The idea is that a project management method helps you cope with these communication issues. The non-Agile project methods, where almost all game developments methods belong, have the following characteristics:

  • You prepare to make a good-enough product that is sell-able to the masses. (This was done to account for the increasing costs of production, and the consumers accepted it because any product was better than none product at all)
  • You try to mitigate the communication risks by using experts to understand the market’s needs. (This was necessary because your goal was to make something that had maximal impact on as many people as possible, but don’t listen to the individual)
  • You plan in advance with what to build for what cost/benefit. (Because you had to prepare a whole factory line, where profits comes from doing it as efficient as possible)
  • You add a line hierarchy with narrow boundaries to manage your workers. (Because of all these activities, the organisation is like a machine where every gear has its place. But those gears can’t do more than they are ment for, for then the whole thing would turn out to be less efficient.)
  • You use mass media and and deals with large selling companies to get your products to the consumers.

But times are changing. A lot of the problems the non-Agile methods accounted for have been minimized in other ways:

  • Creators and consumers can find each other much more easily. (Much less need for all kinds of parties acting as the middle-man. The internet with platforms like / Amazon have brought both much more close together.)
  • Costs of tooling is so much more lower. (You can work from home, get tooling on-demand without upfront payments.)
  • Access to skills has changed radically. (Flex workers all over the world are available to you with specialized services.)
  • Access to information has changed radically. (You can learn basic to advance skills using the internet (and time/practice) where previously the access was the limiting factor now our time is the only limiting factor.)

Add to this that these non-Agile methods come at a huge cost: the distance of the consumer to the creator is almost automatically enlarged, the time to respond to changes is in terms of quarters and years, and with each change large losses in productivity are unavoidable.

As a matter of fact, a lot of organisations are turning to Agile development nowadays. That is because the costs of non-Agile development out wages the benefits, and customers and workers are demanding a shift in culture.

I know from personal experience that introducing Agile methods in a previously non-Agile environments is a really painful process. The whole organisation has to change to adapt Agile, because otherwise perversely incentives will stay in place and try to re-introduce the bad from non-Agile.

This transition is worth the cost. People will be more happy as workers and as consumers. I hope to write some more blogposts on this subject and link to them from this article. I did write already one on game development over at my game dev site.

I will close this blogpost with a how-to. How to know if a decision on organisation structure of project methodology is Agile or not? I try to think of it as follows.

The past is: thinking in advance (official name: input driven). The future is: building what’s needed (official name: output driven).

Remember: All else is just a remnant of the past. People craving for power and thus aligning the organisation to fuel that craving. Departments creating work to stay relevant. So called ‘experts’ that place the consumer at a distance of the creators, significantly worsen the communication between those two.


Wil je weten hoe een gamejam gaat? Of hoe je er een aan zou kunnen pakken? Ik kon maar met moeite ervaringen van anderen vinden. Dus bij dezen, mijn ervaring met de gamejam in januari 2019.

Dag 1

15:30 Cibap Zwolle

Ik doe dit jaar mee aan de gamejam, en ben opweg naar de start bij Cibap in locatie Zwolle. Het programma geeft aan 15:00 inloop, 16:30 start programma. Door een doolhof van gangen zoek ik mijn weg. Ik blijk de verkeerde ingang genomen te hebben, loop t hele gebouw door naar de andere ingang. Daar vind ik de tafel voor inschrijvingen.

25 man ingeschreven, ruimte voor 75 man. Na de eerste kennismaking blijkt dat een aantal naar andere locaties van de gamejam wilden gaan maar dat die vol zaten. Zwolle heeft maar een beperkte game development scene.

We verzamelen ons in de ruimtes die beschikbaar zijn voor de gamejam. Het wachten wordt verzacht met een lolly, uitgereikt bij de inschrijftafel. En ik ben extra in stemming gebracht met een T-Shirt, wat inbegrepen zat bij de gamejam.

17:00 Kickoff

Van 17:00 tot 18:30 hebben we de start van het programma. We verzamelen ons in een grote zaal met podium. Na een korte intro van de leidende personen en de huisregels krijgen we een filmpje te zien van Rami Ismail heeft het over tekenen, dat iedereen een koe kan tekenen, of er anders een pijltje bij kan zetten met ‘koe’. Ik raak geïnspireerd. De intro sluit af met het thema, gebracht door 2 dames die duidelijk onwennig voor de camera een stukje opvoeren over hun gevoel van ‘thuis’.

Dan volgen er een paar team activiteiten. “Om te bepalen welke personen en eigenschappen elkaar aanvullen.” Eerst een snelle check hoeveel tekenaars/ontwerpers er rondlopen. Er blijkt een team te zijn wat al een vaste samenstelling heeft, 3 artistieke mensen en 1 ontwikkelaar. Maar twee artistieke mensen zijn beschikbaar als team-loos. En nog eens 14 ontwikkelaars. Dat begint goed denk ik.

19:00 diner

Vanaf 19:00 is het diner. Het duurt even, maar na een tijdje arriveert het eten in de vorm van lasagne en spaghetti carbonara. Dat was goed eten. De teams moeten gevormd worden. Veel passiviteit, kan ook niet anders vanwege het overgrote deel aan studenten die toch een beetje onzeker zijn over hun kunnen en wat ze willen. Ik begin gewoon mensen te zoeken. De oudste persoon ter plaatse, Kees, is mijn eerste teamlid. 45 jaar, beheerder bij een recent gesloten ziekenhuis, en nu bezig een carrière in game development te starten. Ik vind nog een andere ontwikkelaar, Peter, en nog een ontwikkelaar/artiest genaamd Jan. Allebei studenten. Daarna gaat ieder team naar een eigen ruimte.

20:00 The first mile

Aangekomen in onze ruimte claim ik de leiding. Recent heb ik bij de NS een 2-tal design sprints gevolgd: 1 week lang intensief samenwerken met alle benodigde disciplines van een ontwikkeltraject en gezamenlijk via een creatief proces het te bouwen product bepalen. Dat wilde ik ook hier gaan doen. In de hoop dat ik zou kunnen oefenen in een neutrale faciliterende rol als spelverdeler.

Via een aantal stappen van ideevorming / reductie hebben we bepaald wat wij met elkaar willen bouwen. Tot 23:00 waren wij bezig om plannen te maken. Geen code aangeraakt. Wel veel besloten. Het concept van de designsprint werkt tot nu toe, alleen wel weinig ‘gebouwd’. Hopelijk betaalt het zich terug.

23:00 we call it a day

We breien er een einde aan voor de dag. De meeste teamleden gaan weer naar huis om daar te slapen. Kees maakt gebruik van de slaapplekken die hier op locatie zijn. Kees geeft ook aan dat hij wel de scaffolding op wil zetten in Unity ergens in de komende uren, als hij een momentje vindt naast t slapen.

Dag 2

07:20 thuis, opstaan

Ik had wat moeite met opstaan. Op de heenweg nog even langs de winkel, extra snacks voor tijdens de jam. Niet dat we per se eten en drinken moesten halen, daarin werden we goed voorzien op de locatie, maar toch. Een paar snacks in handbereik leek mij een goed plan. Net zoals paracetamol. Want ik had toch wel last van hoofdpijn door spanning.

09:00 Cibap Zwolle, ontbijt

Ik kom om 9:00 aan. Het ontbijt was van 08:00 tot 10:00, ik bleek vroeg. Er staat brood en beleg klaar. Ik werk snel een broodje naar binnen.

Aan t werk. Kees was blijven slapen op locatie. Helaas voor Kees maar gelukkig voor ons kon Kees niet slapen en heeft hij in de nacht een paar dingen opgezet. Jan kwam rond 10 uur aan.

Peter had moeite met het OV richting Zwolle te geraken. Wat ik best kan begrijpen. Jan en ik hebben t gemak van een auto en in de buurt wonen, met t OV introduceer je meteen moeilijkheden als je in t weekend vroeg ergens wilt zijn.

Ik probeer het team wat leiding te geven door gezamenlijk korte termijn doelen op te laten stellen. We stellen ons als doel om een basis game neer te zetten tot 13:30.


We gaan voor een gewaagd concept: 2 teams moeten een huis veroveren of verdedigen. T liefst is dit multiplayer te spelen op mobile. En we willen de gameplay asynchroon maken, dus een totaal andere ervaring als je team A of B bent.

bepalen wat we in de komende tijd voor elkaar krijgen

We beginnen maar wat te bouwen in Unity. Want hoewel we nog niet helemaal duidelijk hadden wat we gingen bouwen, realiseerden we ons dat we toch echt wel met de code aan de slag moesten. Ik had uitgerekend dat de jam 13 uur aan bouwen beschikbaar had. Dat krijg je als je een 48 uurs jam neemt en het grootste gedeelte van de tijd slaapt en neven activiteiten uitvoert…

Tussendoor maak ik onze pagina op de site. De game krijgt de naam ‘cozy home – human vs other’. We hebben wat problemen om te bepalen tegen wie je nu precies het opneemt. (Het is uiteindelijk geworden, maar dat wisten we toen nog niet.)

We ontdekken dat Unity zijn (simpele) netwerkoplossing aan het uitfaseren is. Omdat het team weinig kennis heeft op dit gebied, met alleen Kees die er eens een Udemy cursus over gevolgd heeft, zien we multiplayer als een steeds groter wordend risico. Na een kort beraad stellen we een simpele random AI voor als tijdelijke placeholder voor t gedrag van de tegenstander, zodat we niet vastlopen als we geen networking voor elkaar krijgen.

Ik heb niet veel kunnen programmeren vanwege al t organiseren en dingen regelen. Mijn bijdrage deze ochtend aan de code was een basis gameplay flow van menu-selectie-game-ending.

eindresultaat van stap 4, door de groep bepaalde slimme combinatie van de best gewaardeerde gameplay ideeën

13:30 Lunch

We worden gevraagd om naar de lunch te komen. Eigenlijk zijn we best tevreden: we hebben een basis game staan met een menu, level, rond lopend mannetje (‘human’), een huisje en een ending.

Er staan belegde broodjes voor ons klaar. Dat is goed geregeld!

14:00 Lekker jammen

We gaan ons en ons spel voorbereiden voor de eerste playtest.

belangrijkste werkzaamheden in beeld, taken verdelen

Een paar ideeën moeten nog geverifieerd worden. Ik stel een papieren playtest voor om de asymmetrische gameplay te testen want die is heel duur om te bouwen en moet wel werken. Verder kwamen we in discussie of een overlord minion aansturende situatie wel genoeg binding met een huis op zou leveren (en dus home gevoel), dus dat was ook iets wat we gingen testen.

We beginnen ons ook te realiseren dat we ook een extra ending kunnen introduceren die het concept veel sterker maakt: de obvious ending is dat je elkaar uit huis jaagt, de niet-obvious is dat je er samen uit komt.

15:00 Playtesting

Wij waren het eerste team aanwezig in de gemeenschappelijke ruimte. Ik heb er alle vertrouwen in omdat ik de papieren playtest uitvoer. We doen ook een playtest van de unity game op een van onze laptops. Kort schiet het door mijn hoofd dat ik eigenlijk niet echt goed heb opgelet of onze game (dat waar het om draait, lol), eigenlijk wel lekker genoeg aanvoelt. Maar ik ga t prototype bedienen, Kees bedient de game en heeft er de laatste fixes op toegepast.

paper prototype

De playtest. Het gevoel van thuis bleek het beste bij geen afstandelijkheid (geen minion AI, geen afstandelijke overlord). Tijdens de playtest werd duidelijk dat de alternatieve ending een grote pre zou opleveren. Verder merkten wij dat mensen gebalanceerde maar hard-hitting acties leuk vinden. We kregen ook feedback waar we niet om gevraagd hadden: voor velen was er t gevoel dat de human onvermijdelijk gaat winnen bij het binnentreden van het huis, en dat de andere partij hoogstens een delay kan veroorzaken.

De paper prototype werd door veel mensen als heel leuk ervaren. Gewoon een beetje rollenspel spelen. En t was maar goed dat we dat hadden, de game zelf wist minder te trekken. Dat de game niet echt trok viel mij niet op omdat ik de paper prototype bediende, maar achteraf gezien waren hier al signalen dat we gameplay wise niet sterk stonden met onze game.

15:30 Aan t werk

De playtest liep tot 16:00, om 15:30 hadden wij al genoeg info.

We stelden weer nieuwe doelen op. Multiplayer zat er voor nu niet meer in. Wel content, veel meer content.
En natuurlijk geen asymmetrische gameplay: besturing en aanzicht aan beide kanten t zelfde, wel wat verschil qua doel en actions. Een groot voordeel want de UI en interactie systeem zou daarmee herbruikbaar worden.

Vol ideeën weer aan de slag
de prioriteiten zijn ook weer bijgesteld
t werk vordert snel, we moeten al weer nieuwe doelen opstellen

18:00 diner

Het eten komt vroeg voor ons gevoel. Er is nog zo veel te doen. Waar wij bij de playtest nog dachten goed op weg te zijn beginnen we ons nu te realiseren hoe veel er nog moet gebeuren. Effectief gezien zouden we vanaf nu nog maar 6 bouw uren beschikbaar hebben. (Tenzij we op slaap gingen bezuinigen of niet meer mee doen met de gemeenschappelijke activiteiten)

Toch maar eten. Het diner smaakt goed. Lekker Hollandse pot (hutspot en/of stampot, rookworst en gehaktballen). Als team beginnen we al wat beter op elkaar ingespeeld te raken. De tongen zijn losser en we hebben leuke gesprekken.

Na het eten snel weer terug naar onze ruimte. Zo langzamerhand weet iedereen wel wat hij moet doen en komt er minder druk bij mij als spelverdeler te liggen.

Maar we worden al snel onderbroken door de leiding van de gamejam. Er is een gemeenschappelijke gebeurtenis gepland.

19:30 Potten en pannen

Met wat tegenzin begeven we ons naar de gemeenschappelijke ruimte. Daar treffen wij jambe’s aan. En een hele inspirerende instructeur.

let’s hear us for Afrika!

Een uur later, met dikke rode handen, gaan we weer aan t werk. Ik merk dat ik ontspannen ben geraakt van zo’n sessie lekker rammen, dit is iets heel anders dan t programmeer/denk werk.

20:30 meters

We hebben inspiratie. Iedereen weet wel iets om mee aan de slag te gaan. De playtesten hadden leuke resultaten waar we iets mee kunnen.

Zo introduceren we de koe-man ipv duivel, zodat spelers zich beter in kunnen leven. We willen dat beide speelbare kanten een goed home-gevoel kunnen opwekken bij de menselijke spelers. Ons spel heet nu officieel ‘cozy home – human vs cowman’.

Qua werk probeer ik meer in mijn flow te komen. Ik ga de code-behind voor alle cowman dingen bouwen. Tot nu toe hadden we alleen de human kant, dus dit wordt een kopie van die kant plus een ingewikkeld switch mechanisme waarmee je kan wisselen tussen human/cowman maar ook tussen aanvallen/verdedigen.

Ik probeer aan te sluiten bij de heersende programmeer stijl. K heb de hele dag al moeite om erin te komen. Kees heeft al zijn ervaring uit zelfstudies, t zijn geen goede programmeer stijlen maar wie ben ik: als t werk dan werkt het. Vooral als we maar weinig tijd hebben dan wil ik mensen niet uit hun flow halen.

Wat betreft de werkwijzen: Peter werkt hetzelfde als Kees. Peter en Kees maken echt de meters in code. Jan maakt vooral de art, en hangt af en toe wat in elkaar in de Unity designer zoals een nette animatie. Jan blijkt behoorlijk kundig in 2D pixelart.

De game code is een mix van service locater patterns en object-naam gebonden zoekacties. Ik ben onzeker of ik hier wat van moet vinden. Ikzelf zou in ieder geval geen naam-gebonden zoekacties doen, en service locater patterns (als er geen DI framework is) beperken tot t hoogstnoodzakelijke. Liever drag-n-drop ik alles aan elkaar via de designer. Maar ja, ik wil geen oordeel hebben over de programmeer stijlen van de anderen. Want misschien heb ik mijzelf een werkwijze in Unity aangeleerd die niet de meest productieve is, weet ik veel. Ik heb niet veel vanuit zelfstudies gewerkt, ik heb mijzelf gewoon Unity programmeren aangeleerd vanuit mijn jaren ervaring in Enterprise software development.

Rond 11 uur word ik het zat. Ik voorzie nieuwe functionaliteit die we heel slecht kunnen integreren zonder fatsoenlijk aan elkaar hangende code. Dus ben ik toch maar begonnen het DI framework, Zenject, te integreren. Ik weet niet of Zenject de oplossing is, maar ik weet wel dat wat er staat al gauw niet meer te houden is.

Het begint al laat te worden. We zijn ver voorbij de 22:00 die ik mijzelf als doel had gesteld om te stoppen. Ik heb heel veel moeite Zenject er in te krijgen, ze blijken een nieuwe versie met breaking changes te hebben en ik ben alleen bekend met de vorige versie. Om 01:00 geef ik het op. Rollback Zenject. Niet alleen vanwege de Zenject versie, maar t is gewoon te groot om in eens om te gooien en te veel code begint bugs te vertonen.


T belangrijkste wat we deze avond hebben bereikt is dat alles er beter uitziet. Betere graphics, de 2 karakters speelbaar, defender en attacker, alle endings… maar wel dus een kater van de code waar ik mij verantwoordelijk voor voel maar wat niet lekker loopt.

Dag 3


Ik moet vandaag op tijd komen vindt ik. Er moet nog zo veel gebeuren dat ik mij ertoe gezet heb er om 7 uur uit te gaan. Wel voel ik mij moe. Heel moe. Even overwoog ik zelfs de handdoek in de ring te gooien, door mijn code-kater van gisteravond gecombineerd met de moeheid en t vele werk wat nog wacht. Maar ik ga door, ik ga voor de ervaring en t ontmoeten van de mensen, niet voor het in 1x kunnen schrijven van een perfecte game.


Als ik aankom bij het gebouw is het stil. Ik word door de bewaking binnen gelaten. De gangen zijn verlaten. Ons hok is donker: Kees ligt er nog te slapen. Dan maar naar het ontbijt. Dat staat nog niet klaar. Ik loop terug en maak Kees wakker.. We zetten wat ramen open om de slaaplucht eruit te krijgen, en ik ga weer aan t werk.

Peter bleek zich nu echt verslapen te hebben, hij kan pas na half 11 komen vanwege t OV. Jammer, want hij was gisteravond juist goed bezig aan een bepaalde feature, maar die was nog niet af toen hij weg ging.

Jan is steady. Hij komt stipt na het ontbijt om 10 uur, net zoals gisteren.

We zijn lekker bezig. Iedereen zit in z’n focus zone. Ik ben druk bezig de gameflow in orde te krijgen. Er zijn her-en-der bugs die niemand er echt uit krijgt, ik fix ze door nieuwe aanpakken te implementeren.

Peter heeft problemen dingen op de juiste plek in code te krijgen. Ik voorzie nut van DI, dus ik probeer, nu met een helder hoofd, opnieuw Zenject er in te hangen. Maar dan alleen de hoogstnodige dingen in t DI framework te hangen. Dat slaagt in korte tijd.

We hebben veel last van merge conflicten. Unity heeft scene bestanden waar vanzelf veel werk in gebeurd maar die heel lastig mergen. Tel daar een slechte pull-push hygiëne bij op en je hebt recept voor veel frustratie en verloren werk. Frustraties beginnen op te lopen.

de laatste loodjes… wegen het zwaarste

13:30 Eten

Snel weet wat van die belegde broodjes naar binnen werken. T valt mij op dat iedereen door blijft werken, even langs de gemeenschappelijke ruimte loopt om wat broodjes te halen, en daarna weer teruggaat.

14:00 Laatste loodjes

Nog 1 uur over tot aan de upload die van 15:00 tot 16:00 duurt.

We komen in een crisis terecht. Jan stelt terecht vast dat er nog behoorlijk wat schort aan de gameplay. Ik geef hem groot gelijk, maar geef ook toe dat hij degene is met t meeste gevoel ervoor en dat hij zelf met verbeteringen zal moeten komen omdat de anderen ze simpelweg niet zien. Ik mis Kees als backup, Kees was ergens anders in een hok gaan zitten om wat dingen te fixen vanwege concentratie issues. Ik probeer Jan op te beuren en geef aan dat we van heel ver komen en al veel bereikt hebben. Maar het mag niet baten, Jan geeft aan niet tevreden te zijn en niet zijn naam onder de game te willen hebben. Hij gooit de handdoek in de ring en zegt wel met wat dingen bezig te gaan die hij nog ziet liggen in t visuele design. Teveel stress.

Toch kwam deze bij mij hard aan. Ik hoopte iedereen aan boord te kunnen houden door gezamenlijke doelen te blijven formuleren, maar Jan had nu effectief aangegeven dat een gezamenlijk doel nog niet een goed doel betekent.

Ik zie ook de gameplay issues en de vele bugs. Ik was wat ongenuanceerd naar Jan toe dat ik geen gameplay gevoel heb, ik heb best een idee wat belangrijk is. Maar ik ga dat niet het team opleggen had ik mij bedacht… en bij dezen ben ik net zoals Jan niet daadkrachtig genoeg om het voortouw te nemen.

Ik verleg uiteindelijk toch maar de focus van mijn werk, van afronden van de features die we gezamenlijk afgesproken hadden tot nu dan maar ad-hock de feeling op orde krijgen. Maar niet in overleg met het team, dat durf ik niet aan met de spanning die er nu is.

15:30, chaos. Issues.

Intussen blijkt dat de dead-line wat vloeibaarder is dan van tevoren gesteld, gelukkig. 17:00 is de max wat betreft de upload. Jurering gebeurd lokaal, om 17:30. We kunnen ons dus tot die tijd bezighouden met verbeteringen.

17:30 Presentatie en bugs

Het is zo ver. We moeten de game presenteren. Er blijken een paar nasty bugs in geslopen te zijn in de laatste uren. Deel van de normale ending triggert niet, andere ending geeft aan dat je gewonnen hebt ipv verloren. Speciale ending werkt gelukkig wel. Gameplay wise hebben we een probleem: men kan zichzelf insluiten wat tot gevolg heeft dat we de game af moeten sluiten met Alt-F4… want we hebben nog geen menu/esc ingebouwd.

De game, zoals hij speelbaar was tijdens de jurering

Maar er is nog meer: weinig aankleden van de level, actions werken maar half, actions hebben geen nut, AI biedt geen noemenswaardige tegenstand, geen noemenswaardige geluidseffecten/muziek.

Onze game tijdens de laatste playtest / jurering

Ik ben blij dat men uiteindelijk ons nog credits heeft gegeven voor onze ‘betere’ alternative-ending die verstopt in de game zat. En voor de koe. We wisten al dat die features mensen blij zouden maken, en gelukkig waren ze opgemerkt.


Al met al ben ik heel tevreden met deze eerste gamejam. Veel nieuwe mensen ontmoet en connecties gemaakt. Werkwijzen van anderen kunnen zien en meemaken. Daar was het mij allemaal om te doen. Een werkende (soort van) game afgeleverd hebben was voor mij een bonus, en dat is ook behaald.

Ons team, dank voor de leuke tijd!

Maar ik was wel kapot. Van een normale werkweek direct door naar een gamejam, geen weekend, en toen weer een werkweek. Het was het waard.

Nog wat aanvullende gegevens, voor de geïnteresseerden:

Zilveren kogel

Een vraag die ik mij als software ontwikkelaar vaak stel is: ‘is er behoefte aan het stuk software waar ik nu aan bouw?’

Een oplossing

Misschien herken je dit: je wilt een proces verbeteren/versimpelen en je komt tot de conclusie dat dit kan met een stuk software. Dus je maakt een stuk software.
Iedereen blij, vooral omdat er überhaupt naar een wens geluisterd wordt, en men gaat vrolijk aan de slag met je stuk software.

Maar werkt het

Maar na een tijdje begin je jezelf af te vragen of je wel slim bent geweest. Want je krijgt feedback. Complexe processen worden zichtbaar. Waarvan je merkt dat deze de software een stuk complexer maken dan dat je eerst voor ogen had.
En als kers op de taart komen er mensen die je op bestaande stukken software wijzen die ook, min of meer, ‘het zelfde doen’.
Continue reading “Zilveren kogel”

Een app die niet werkt, wat nu?

Waarom je de software die je gebruikt wilt blijven ontwikkelen. (En niet wilt stoppen en het over een andere boeg gooien.)


Nadat wij goed en wel aan de slag waren met de liturgie generator bleek dat we een nieuw probleem hadden: Presentaties waarop willekeurig elementen (tot zelfs volledige slides) ontbraken, het generatie proces wat op willekeurige momenten stopte en zelfs het totaal niet opgestart krijgen op bepaalde computers.

Wat nu

In principe was de applicatie een prima softwareoplossing voor ons druk probleem: we hadden de presentatie samensteltijd tot 1/3 teruggebracht.

Maar het probleem van onbetrouwbare resultaten begon wel tot vragen te leiden en zelfs tot suggesties om een volledige andere softwareoplossing te gaan gebruiken.

Continue reading “Een app die niet werkt, wat nu?”