What is going to be done for next major release? This will be reviled in next post, I'm still working on the feature list and I've already started working on something. I'm weighing how much refactoring should I do because I really want to clean up some things but the downside of refactoring is that features doesn't get made during that time. So I've started new milestone to by refactoring the biggest thorn in the side. Now is the best time while there is no psychological pressure to work on polish, feels like I have all the time in the world and it's better to do breaking changes early with plenty of time to test them thoroughly. In last version I've been working on removing text template code generators but I had to keep state handling ones due to complexity and their time has come to an end.
In Stareater code game data is split in following categories:
- States - facts of the game world such as star positions, which planets are colonized and by whom, which technologies players have researched and so on.
- Orders - how players want to change the state. This includes building queues, technology development order, audience request and so on.
- Derivates - implications of states and orders. Population growth for example is calculated from colony's current population, population limit and "housing" building which converts industrial production to population.
- Statics - assortment of stuff in the game. Which technologies there are, kinds of ship equipment, kinds of buildings and so on.
When it comes to juggling data statics are simple, they are loaded once and that's it, derivates are recalculated when needed so they don't require much management either but states and orders have to be copied, saved to a file and loaded back. Ordinary mortal programmer would simply write functions for each operation in each data type. Maybe I would too if it's was a smaller project but in this one there are currently 20 state and order data types with total of 82 attributes (members/properties/fields). That's a lot of stuff keep in mind and remember to update when adding new features. So like every engineer I've decided to let computer do the bookkeeping for me and that's where T4 text template came to play. I'd simply list which attributes a type has and for each attribute it would generate logic for initialization, copying, saving and loading. It sound awesome in theory but T4 is hard to debug (at least was at the time) and there were always some edge cases which were hard to solve with general approach.
Developing and updating T4 based solution took me at least two months, in total making it almost 10% of effort since v0.5 rewrite. New system already took a month to develop but I'm confident it won't take much time to maintain. Firstly, it already works, secondly it's easier to work with since it's pure C# code. I also simplified data a bit in order to make it work, some relations were really complicated and required a certain unintuitive order of operations to get stuff done.
How does this new "state engine" works and why didn't I implement it first time around? In C# there is something called reflection and I tend to call it "dark magic". It allows you to get information about data types while the program is running, information such as which attributes a type has, how they are called in source code, which types does the type inherit, reading and writing values where you normally can't and many more. All of this comes at the price of quite slow performance. Also there is another form of "magic", so called expressions trees which basically let's you create more program logic while the program is running. At first I was concerned whether it's a good idea (how fast is compilation, would antivirus freak out) but I've found out that Microsoft's own database access functions use so it's not something foreign to the world. The price is only a slowdown on first use (compilation actually), further uses work almost as fast as native code. New state engine uses both schools of magic, reflection for gathering data and build up engine and compiled expression trees to do the actual operations but I tried to keep them to a minimum since they don't make very readable code. It's much more readable then T4 templates, true, but still not self-explanatory on a first glance as normal C# code.
This engine didn't come out of a blue either, I've been experimenting with technology a year ago and developed a small prototype project to test out those "magics". Now that a new engine is made, there is some minor code cleanup is left to do, full removal of remaining T4 templates and verification if all state and order data types save and load properly. God, I need to automate this somehow but only thing that comes to mind is to make a test suite which would take another month of making features. Back to compiling feature list for the milestone, one thing is certain, organizations are going to have a tangible effect.
Developing and updating T4 based solution took me at least two months, in total making it almost 10% of effort since v0.5 rewrite. New system already took a month to develop but I'm confident it won't take much time to maintain. Firstly, it already works, secondly it's easier to work with since it's pure C# code. I also simplified data a bit in order to make it work, some relations were really complicated and required a certain unintuitive order of operations to get stuff done.
How does this new "state engine" works and why didn't I implement it first time around? In C# there is something called reflection and I tend to call it "dark magic". It allows you to get information about data types while the program is running, information such as which attributes a type has, how they are called in source code, which types does the type inherit, reading and writing values where you normally can't and many more. All of this comes at the price of quite slow performance. Also there is another form of "magic", so called expressions trees which basically let's you create more program logic while the program is running. At first I was concerned whether it's a good idea (how fast is compilation, would antivirus freak out) but I've found out that Microsoft's own database access functions use so it's not something foreign to the world. The price is only a slowdown on first use (compilation actually), further uses work almost as fast as native code. New state engine uses both schools of magic, reflection for gathering data and build up engine and compiled expression trees to do the actual operations but I tried to keep them to a minimum since they don't make very readable code. It's much more readable then T4 templates, true, but still not self-explanatory on a first glance as normal C# code.
This engine didn't come out of a blue either, I've been experimenting with technology a year ago and developed a small prototype project to test out those "magics". Now that a new engine is made, there is some minor code cleanup is left to do, full removal of remaining T4 templates and verification if all state and order data types save and load properly. God, I need to automate this somehow but only thing that comes to mind is to make a test suite which would take another month of making features. Back to compiling feature list for the milestone, one thing is certain, organizations are going to have a tangible effect.
Nema komentara:
Objavi komentar