In my last post, there were some comments from Olmo about breaking changes. Olmo is one of the best .NET developers I know, and he offered some very interesting ideas on how to handle them (for example, leveraging Roslyn to fix breaking changes).
Our position about breaking changes is that they are bad, very bad. We don’t want them, and we will try to avoid them as much as possible. We think it is a pain to work in a project and “fear” updating it because every time you do you have to fix your code to make it work again.
But, the reality is that breaking changes exist, and they will happen no matter how hard we try to avoid them. While we have used Wave in-house quite a lot, we are so used to it that we can miss issues that would be glaring for someone starting with it without prior knowledge. For example we have had a new person using it for building demos, and we got very interesting feedback from him. I am sure that when we release this situation will repeat itself a lot.
So, our idea so far in this front is to do something similar to how the XNA team performed their releases: try to avoid breaking changes in minor releases unless it’s a very important issue, but there will be major releases where we will put in all the minor changes we did not add to avoid breaking things. Not every major release will have to be like that, sometimes a release will just add support to a new platform, add new capabilities to the engine because of platforms evolution,… But we will do our best to not break things on minor updates so people can work on their projects confident that they will not have to lose time because of an upgrade.
When you design a framework/engine/library, there is always the fact that you have to think about the “surface area” of the API: how many classes, methods,… the user will see and be able to use.
In Wave, we have divided the engine in several assemblies:
- WaveEngine.Common: this assembly contains the most basic functionality of the engine. For example, the math library sits here. It also contains a set of core interfaces that represent the engine in its most barebones state: IAdapter, IGraphicDevice, IIOManager, IInput,…
- WaveEngine.Adapter: this is not really an assembly, but a set of assemblies with the same name, one for each platform we support. An adapter is simply the code that is needed for the engine to work on a given platform. These Adapters implement the core interfaces defined in WaveEngine.Common (IAdapter,…).
- WaveEngine.Framework: this is the assembly the users of Wave Engine will be using to code. Framework wraps over the low level operations defined in the core interfaces, and presents the end user with a higher level API that is more powerful and simpler to use.
- There are a few other assemblies, but they are not more extra sugar candy and not mandatory really (WaveEngine.Components, WaveEngine.Materials,…).
So, in a perfect world, when a user starts creating a project with Wave Engine, he will just reference Framework and start working happily. In reality, that person will probably also need to reference Common, as some types that sit there (specially the math types) are commonly needed in a normal project.
Once you add a reference to Common, there is a problem. All the core interfaces (and a few other things) are public, but they are not designed to be used when making a game, they are designed to be used when writting an adapter to support a platform on where to run the engine. But the user will see them nevertheless, as they are public because they have to be consumed for the Adapter assemblies.
This is somewhat problematic. If by mistake we expose one of those levels interfaces in Framework (for example we used to have quite a few references to IAdapter), the user can bypass the high level API (by mistake or by his own choice) and then start using things that are not designed to be used in his scenario (making a game). A solution would be to split the Common assembly, one with really basic types, and another with the types used in the adapters, but the problem is that those assemblies would be quite small if separated.
In the end, we have made Framework so none of this classes and interfaces are exposed publicly anywhere, so the user doesn’t have a way to get a reference to an object implementing them (they are always interfaces or abstract classes). The user could implement them himself, but that doesn’t make much sense, so we do not worry about that case. The user could also get them using reflection, but we do not think that’s an interesting scenario to take into account either.
So, the main place where we should spend more time (and where we have spent more time by far) making sure the public API was solid is WaveEngine.Framework. Take into account that Wave Engine was developed at the same time as our first game, ByeByeBrain (BBB), was developed, so both evolved quite a lot during their main development (which lasted more or less a year). It was an interesting thing for me to see how the olders part of the code where for example accessing Common, while the newer ones were using Framework, it shows how the engine evolved, providing only very basic services at the start, and then growing to provide more higher level and powerful classes to simplify daily scenarios, or handle some platform differences that even with Common couldn’t be abstracted. For example serialization works in some minor details differently in .NET (and different between the PC and the Xbox360) and Monotouch/Monodroid.
As we dediced to review Framework, we went through all public attributes, properties and methods and start deciding what to do with every one of them. Some things were public, but were not used outside Framework (maybe it was thought they would be useful but they were not in the end), and were made internal. Others were public and where used, but the same could be achieved in the same way and we did not want to expose two ways of doing the same thing. And so on and on. In general, we tried to make as much as possible private/protected/internal, yet it is hard sometimes to gauge if you have done it right as we have only BBB as a case study (and some internal samples, but they are fairly simple). Did we make something internal because it was not useful or it was just not useful in BBB? That was a very important question for us, and sometimes we did not have a clear idea of what was the answer, so in those cases we decided to go with hiding things, as making something public has less chances of breaking things than making something private.
We think in the end we have ended with a very clean API, with enough power to be usable but not overly complex, but we need to validate it ourselves first. Right now the current Wave Engine build and BBB sit in a Stable branch, while this new rewrite sits in a Development branch, which does not compile BBB yet. We have now some work to migrate BBB to this new branch and see how it performs in a “real scenario”. BBB is a very graphic intensive game and during its original fast development there were some design decissions that are lost today. For example, did we expose a low level operation from the IAdapter because using the high level version was too slow for a common scenario? Or more importantly: have we introduced some subtle bug without realizing? Those are the questions we will be able to answer when we port BBB and validate our work. We have ported the samples and they work nicely, but switching BBB while we finished its release in iOS and Android was simply not feasible for a small team like us. Now that the iOS has been released and the Android version is coming to an end, we can start with this final validation and fix any pending issues we find.
My current job in Weekend Game Studio is to review the codebase of Wave Engine. We are preparing for a public release, and we want to try to make sure the engine API is as good as we are able to. Even if I have just been playing with it for less than two months, I am the one in charge of the review for one reason: in general the more you work in something, the less you see its problems (this applies to many other things, not just coding).
Of course, given that I have used the engine very little, sometimes I give feedback that simply shows my ignorance of the product, but when the engine team has to explain me why they made a certain decision, they also force themselves to think about it, which helps us a lot in the long run.
On Monday, one of the last things I saw in the code, is that the class Entity was sealed. I spent part of the evening at home remembering a topic that is somewhat controversial when writing a library: whether classes in the library should be sealed or not.
I used to be pro-sealing everything, but my views have changed with time. I think I started to change my opinion after talking in one MVP Summit with Michael Cummings about the subject. Michael has been maintaining the engine Axiom for years, and he was very in favor of not sealing classes (if I remember right :) ). I have also hear this complaint from time to time on forums or blogs when using some libraries (for example XNA).
So while I now think it is better not to seal unless you have a very good reason, I am not totally convinced about it. On Tuesday I decided to put a tweet about the subject, and I got a very interesting conversation with Rodrigo Corral, Jorge Serrano, and Enrique Amoedo.
First thing I usually hit when I have a design doubt is Microsoft Design Guidelines for Developing Class Libraries. In the Design for Extensibility section there are two topics about unsealed and sealed classes. They are pretty short to read, and they seem to be very in favor of not sealing.
Consider unsealed classes with no virtual or protected members as a great way to provide inexpensive, yet much appreciated, extensibility to a framework. By default, most classes should not be sealed.
And:
Do not seal classes without having a good reason to do so. Do not assume that because you do not see a scenario in which extending a class would be desirable, that it is appropriate to seal the class.
There are also quite a few interesting posts about the subject around the internet, most with very long arguments about the topic. This is one of them, which even includes a comment about the subject from Eric Lippert.
The biggest argument usually for sealing, is that if something was not designed (and tested) for extensibility, it should be sealed. Allowing inheritance could break the class, or other classes that depend on that class in ways that are hard to predict, and the cost of maintaining and testing something unsealed is much bigger. Sealing makes the live of the library developer easier (classes cost lest effort), and avoids the user shooting himself on the foot by extending something that was not designed to it (or that the user didn’t understand very well before extending).
The argument for not sealing is that library developers can not imagine every possible use their users may give to a given class, so sealing is forbidding scenarios that may be interesting for the users of such a library. If you have a library that does not allow the users to do what they want, you have unhappy users which is a problem.
In my experience, I have hear very few times users complain because how they shoot themselves on the foot by extending something that shouldn’t be extended. I like the idea of sealing as a way of warning a user that “you should inherit from here at your own risk”, but the implementation of sealed is too restrictive. On the other hand, I have hear quite a few times users complain about not been able to inherit from something sealed.
The biggest problem when sealing is when the sealed class appears as a parameter of a method. In that case, there is no way to pass an specialization of that class to the method, so users need to do pretty strange workarounds. Library developers have a way to avoid this problem, and that is that if the class is sealed, you do not pass it as a parameter, and instead you pass an interface and make your sealed class implement that interface. That is somewhat better, but it seems too clunky on my eyes:
- First, you have created an interface just for the sake of creating an interface. It was not because it made sense, it was just because you needed a workaround.
- Second, you have added more weight to your API and library: the interface, and probably at least one public implementation of it.
- Third, interfaces version very badly, as any change on them will mean a breaking change on every implementation out there. Your users upgrade to the last version of your library, and suddenly nothing compiles. Users hate that a lot in my experience, and I have seen the horror of versioning interfaces (in ArcGIS API) and that is even worse.
The only point to which I can agree is that sealing a class makes things easier for me, the library developer. But given that my final objective is making the live of my users easier and not mine (unless the cost is horrible), I prefer going with not sealing most of the time. On the other side, the only thing that keeps me from being 100% sure about that decision is that unsealing a class is not a breaking change, so depending on how fast we were able to service new versions of Wave Engine, it could become a non-issue (and only unseal when someone finds a case where it would be needed).
This year Weekend Game Studio (the gaming part of Plain Concepts, the company where I work now), decided to have a booth and give a sponsored talk in GDC 2012. Even if I had joined the company just a month earlier, I was lucky enough to get to go also to GDC (and be one of the two speakers of the conference, which was a little stressful to say the least :p).
The idea of the GDC was to showcase our two first games, the tower defense ByeByeBrain and the web game The Cure. We also wanted to talk about our own internal game engine, Wave Engine, and show how the same code could run in WP7, iOS, Android, web, and PC.
So this is a postmortem from my point of view of things that went right and things that went wrong.
What went right
Weekend Game Studio, and the Seattle office of Plain Concepts have just born a little more than a year ago, and they are in the process of getting firmly established. So going to GDC, giving a sponsored talk,… was a huge expense for us. We also decided to go to GDC pretty late, so in the end, we could only get a booth on one of the corners of the expo pavilion. We also could not get huge plasma TVs, have a ton of goodies to give away,... as our budget was pretty limited.
In general, it looked like our booth was going to be pretty “gray/boring”, as we didn’t have the money to just make it stand out. So we decided to go other route. The artist of ByeByeBrain had the idea of making the booth seem like a zombie refuge, and have us disguised as zombies. Even if we weren’t very sure at the start of the idea, it was a huge success. Everyone noticed us immediately while walking around, and a lot of people stopped to talk just to say that they loved the booth, which in turn allowed us to just ask about them and keep the conversation going.
I am sure that without the thematic booth we would have had quite a few visitors (the expo floor was very busy specially the first day), but the great decoration, the disguises,… made GDC much more of a success and allowed us to meet much more people (from students to very high profile execs).
Another thing that went right, and it may seem a little obvious, was the decision of going to GDC. We were not sure if we would be able to recoup the costs of it, but in the end I think it was more than justified. We had business meetings for projects all day long, from very small projects, to really big opportunities.
We also got a lot of portfolios from professionals searching for a company to join or for freelancing work. Right now Plain Concepts has a lot of programmers and web designers, but we lack severely in other areas important for games, like 3D artists, game designers, composers, sound engineers,… We have built thanks to GDC a nice pool of people we can contact in the future for work and collaborations, and it is way nicer to have met and talked with that person face to face than just by email.
And we also got a lot of portfolios from students interested in internships, which took us totally by surprise. I had given classes in university before, and while it had its ups and downs, it was something I enjoyed a lot. I think having interns working with us, and the experience of guiding them and teaching them would be quite interesting.
What went wrong
Sadly, not everything went great, there are a few things that we will take into account for next editions to avoid doing the same mistakes.
First, we had a problem with our booth, as the booth we received was not the booth we were expecting (we were missing some lateral walls where we were going to hang part of our decoration). The GDC organization was very unhelpful, as they said it was a mistake on our part for misunderstanding the booths and their emails (which honestly could have been written much clearly, and we asked very specific questions in most of them). Even after talking with them for a while they basically told us that there was nothing they could do. But hopefully, the company building the booths itself, was able to help us (for a price, everything has a price down there :p), and we were able to have some supports to hang our booth decoration. Even if we had to pay, the attitude of the company building the booths was very helpful and friendly, so it is appreciated.
Our second mistake was not been really prepared for GDC. It was our first time and we didn’t know what to expect. First day we came to the booth with not many business cards, and we had run out of them in less than two hours :S The booth was full of people most of the time (in general, the first day the whole expo was full of people), and we were a little overwhelmed by how many questions and interests we got that day. For example, we started getting business cards, and the first day we failed to take notes on most of them (if it was someone searching for job, freelancer, a future partner, a distributor,…). On the next days we carried many more cards and we took notes of everyone, which helped a lot to organize things.
Another example of how badly prepared we were was when we got students asking for internships in Weekend. We are a company founded by Spanish people (and pretty young in the states), so we had no idea of what paperwork (if any) was needed to have an intern working with us. Now we think it is funny that we had not even thought of that before going to GDC, but we could have never imagined that students would be interested in doing an internship with us.
I also think that something that went “wrong”, although it’s much more subjective, is that we could not leave the stand and check the rest of the GDC. We were only three people on the stand, and David was quite often out on meetings, so Anton and I had to stay pretty much all the time there chatting with people and showcasing ByeByeBrain, the Cure, and Wave Engine. I would have liked though to see some of the conferences, and the other pavilions.
What I have no idea how it went
And, even after all of that, there is one thing I have no idea if went right or not, and that was my sponsored talk about Wave Engine. One one side, we had forty people there, that was much more than we were expecting (and more given how many things were happening at the same time we gave the talk). But on the other side I had no questions in the end (publicly, I had a few of them privately), and I can’t stop thinking that probably people were expecting a much more technical talk. I think most talks in GDC are very heavy on the technical side as the general public of GDC has a high degree of knowledge, but ours wasn’t very deep. I put some basic code examples that explained the engine philosophy, but I didn’t enter in all the gory details of making the adapters for each platform and so on.
Nevertheless it seems the GDC organization sends the evaluations to the speakers, so I really want to read them and see what things can be improved if I repeat the experience. Getting evaluations after a talk can be harsh sometimes, but they are great tools for improving. I remember the evaluation of my first talk ever (a talk for Microsoft University Tour in Spain), that was a total disaster, but it contained lots of very useful comments, so it was a welcomed thing.
Summary
So that’s all more or less for GDC 2012. After the Expo when we returned to Seattle we spend the next week organizing all the business cards, sending emails, checking portfolios, samples, and demo reels,… It was an interesting week, and I have to say that I saw lots of impressive portfolios out there.
Btw, I would like to add that we were lucky to have the people of Trioviz as one of our neighbors, they were super fun people, and their 3D technology was simply awesome. I tried Arkham City for a while and the 3D effect was truly nice. And they gave us some 3D Glasses :) We had also some very nice neighbors just in front of us, that offered us every day tea and other refreshments, but I sadly don’t remember their name (and I can’t seem to find the 2012 GDC Expo floor map).
I really hope we repeat next year, it was a great personal experience, and we did a lot of business so it was also worth for the company (I guess, I don’t know how much did it cost us exactly to go there, but I think the visibility and contacts we gained does offset the costs).
So, yesterday was my last day at C Tech Development Corporation. It was my last day as a freelancer too. These last three years have been a great learning experience, and I feel I have grown quite a lot as a developer.
I landed the job thanks to my work in the old Jad Engine, where I met Reed and Bengt, and I honestly think I have been very lucky to be working with them, along Adam and Devlin. They are very talented devs, and I have learned from each of them as much as I have been able. I am proud also of the product we have been build during this time: EnterVol, an ArcGIS plugin that adds volumetric analysis of chemistry/geology data. Internally EnterVol is a really interesting piece of software, using WPF, WCF, TPL,... It is rather complicated, but also full of very elegant design decisions and code. I really hope it brings lots of new customers to C Tech, they deserve it :)
I want to give a special mention to Reed, my boss. Reed Copsey is a Microsoft MVP in C#, maybe not as known as other famous people on that area, but he is one of the best (you can check Stack Overflow and see him in the first page of top users ;) Not only he is an outstanding developer, capable of facing any problem you throw at him (seriously, he can jump from DB, to graphics, to algorithms, to WCF, and not even blink), he has been also an outstanding boss. He has lead the team carefully, dividing the job, keeping an eye on us, helping when needed, and he has been more than understanding with some cultural differences that exist between Spain and USA, specially regarding holidays. Given how hard is to find a good boss, I really appreciate this.
And for the future? Well, I am moving to Plain Concepts, a Spanish Microsoft partner. I am very happy of this for several reasons. First and mostly, because of the people: I know quite a lot of people in the company from old jobs, Microsoft events,… It is always nice to work with people you know you already get along well, and even nicer when they are technical leaders in their fields. I hope I’ll learn quite a few new things from all of them. Oh, and the company average age is quite young too :)
Second, because Plain Concepts has just started developing games, via Weekend Game Studio. They have already released two games and are developing their own multiplatform game engine called Wave (which powers Bye Bye Brain). Wave is mostly the work of two people, one if them is Javier Canton, another fellow Spanish XNA/DX MVP. I really look forward working with them on the engine and improving it in the future. And releasing quite a few games :)
And third, because I’ll be moving to their Seattle office (if I get the visa, come on immigration), which is a huge change for me. I needed to get out of my comfort zone a little, and I wanted a change after been working so long remotely at home, and this achieves it by long. It also allows me to experience what it means to live abroad for a long time, something I’m very curious to discover.
So, one path ends, and another starts, I am really eager to discover how this new part of my life and professional career will develop.
More Posts:
Next page »