Sunday, June 5, 2022

Map Compasses Retrospective

I started the map compasses project with two primary goals.  First, to create a procedural map compass generator, and secondly to experiment with sharing my code.

Generating map compasses has been on my list since seeing Oleg's version a couple of years ago.  Oleg was kind enough to share his code with me, but I decided that the compass roses he generates were not usually suitable for my maps and decided to write my own.  I also wanted to experiment with creating what I think of as a conservative generator.

There's usually a trade-off in procedural generation between creativity and acceptability.  If you build a procedural generator that can be very creative and come up with unusual and unique solutions, it's usually the case that the generator will produce a substantial fraction of solutions that aren't acceptable.  In the past I've leaned to the creative side of the spectrum, and (for example) my city icon generator can invent a wide variety of city icons, but there's a good chance that any particular icon won't be acceptable for one reason or another.  Creative generators tend to be only lightly constrained.  They're able to “break the rules" and sometimes that produces a wonderful result, but often it produces a poor result.  That's why a lot of artistic endeavors have “rules of thumb" -- they outline the areas where good results heavily outweigh poor results -- and if you break those rules you can sometimes do something really new, but often at the cost of a lot of failures.

In general, you might not think it a problem to have a procedural generator that occasionally produces a bad result.  Just generate a new result until you get one you like.  And in isolation, that's fine.  But problems arise when you have a program like Dragons Abound which incorporates a number of separate procedural generation systems.  Even though each PG system may only occasionally throw up a bad design, when you have several running in parallel, the chances of at least one of them providing a poor result goes up.  And this is particularly annoying when your program can take several minutes to run.  Having to run over and over trying to hit upon a map where everything is good is annoying.  

And with creative generators, I always think that I'll look at the output and think about the good and bad results and then add those insights back into the generator to improve the good/bad balance.  For example, I might see that “city walls" in city icons only turn out well in certain specific instances and then go back and tune the rule set accordingly.  But in practice, I don't really ever do that.  By the time I'm seeing the bad city icon results, I've moved on to other problems, and about all I ever do at that point is just turn off a rule entirely.  No more city walls, that fixed the problem!

For those reasons, when I started the map compass generator I leaned in the other direction and tried to create rules that would almost always produce an acceptable result.  Overall, I'm happy with how that decision turned out.  The generator mostly creates acceptable (if “vanilla") results, and I don't usually have to re-run the generator to avoid a bad result.  I also think that on a practical level, I'm more likely to see an example of a compass I like and then go back and add that to the generator.  But we'll have to see how that works out.

One feature I thought about while creating of the compass map generator is a “temperature" control.  The idea would be to have a dial (parameter) that I could turn during generation to be either conservative (cold) or more creative (hot).  With rule-based systems, one way this could work would be to assign a temperature range to every option in a rule, e.g., 

<radialElement> => {0} <thinCircle> | {10} <thickCircle> | {50} <weirdCircle>
Here the number in the curly brackets indicates the lowest temperature for this option, i.e., thinCircle could be used even at the coldest setting, but weirdCircle wouldn't be a possibility until you turned the temperature up to 50 or above. This would give me the option to play it safe or gamble, depending upon what I was trying to do.  That's something I'll be thinking about for the future.  

The second goal for map compass generation was to experiment with sharing my code.  I often get asked to share my code, and I usually feel a little guilty saying no.  After all, I got started down the Dragons Abound road because years ago Martin O'Leary was generous enough to share his map generator, and in a way I feel I owe the same grace to the community.  And I often hear the benefits of open source lauded -- maybe I was missing out on the benefits of a thriving community around the Dragons Abound code.  But at the same time, I recognized that sharing my code would have some substantial costs -- not just eliminating any commercial value to the code, but also in terms of the time and energy it would take to share.  I didn't really have any good way to judge whether that balance would be positive or negative for Dragons Abound, so I decided to do an experiment with sharing some code to see how hard it was and how it was received.  Map compasses was the first thing that came along that fit the bill.

In terms of the mechanics of sharing, it proved to be about as difficult as I had expected.  One of the challenges was in producing code as a companion to the blog entries.  I wanted readers to be able to access and run the code as it was in each blog entry.  I ended up doing this by using Git branches -- there's a separate Git branch in the repository for each of the 18 blog entries in the compass series.  This turned out fine, but it was a bit of work.  I had to get used to working in a separate branch for each blog entry, and remembering to start a new branch with each new entry, and so on.  There were several occasions where I screwed this up and had to spend an evening fixing up the branches.

I also didn't want to release branches ahead of the blog entries, and since Git doesn't offer a way to make private branches public (at least not at the free level), it meant I couldn't actually use Github until I was ready to release the code. 

 I also wanted to keep the code self-contained to make it as easy as possible for people to grab the code and start using it.  This involved including small web servers for Windows, Linux and Mac in the repositories, as well as providing a starting web page.

Finally, I wanted to give people a way to run the code online if they just wanted to see the generator run.  I did this using Netlify and once I had established an account, set up a workflow and so on, this was fairly straightforward.  For each new branch I created a new site, gave it a recognizable name, and Netlify handled the rest.  This was probably my most pleasant tool interaction.

There were also some costs in writing the code.  First, I naturally took more care in writing code that I intended to share.  I tried to keep the code straightforward and understandable, so I often avoid things like list comprehensions that less experienced programmers might find confusing.  I also took care to comment anything that might need explanation, and to keep my formatting consistent.  In my “regular" Dragons Abound programming I often leave old versions of functions or temporary code in place as a reminder of the development process or in case I might need them again, but in the shared code I edited such things out.

Another unexpected cost was that I had to copy or rewrite a lot of utility functionality.  In Dragons Abound I have a large library of utility functions to do things like manipulate polygons, work with the map, draw lines, and so on.  Using those in the compass generation required either including lots of Dragons Abound code, spending time adapting the code for the compass generator, or rewriting the functionality.  I ended up mostly adapting/rewriting the code to keep the overall project as simple and understandable as possible.

A final cost of sharing the code was that I took the time at the end of each blog posting to suggest ways in which people might extend or modify the code for that posting.  Sometimes these ideas were extensions of what I'd done in that posting, and sometimes they were foreshadowing something coming in a later blog post.

Overall, the costs of sharing were considerable. I'd say it slowed down my development pace by 50% or perhaps more.  On the other hand, did code sharing have any positive benefits?

Well... A few people seemed to look at the code:

I'd typically get a couple of visitors to the Github repository after every new blog post. 8 users “starred" the repository.  Nobody forked the repository or tried to make a commit to any of the branches.  Although I asked in most blog posts for people to share anything they'd done with the code, I got no comments or emails indicating that anyone had used the code.  (I thought about leaving an obvious bug in the code to see if that generated any feedback but in the end decided against it.)

One of the benefits often touted for open-source code is outside contributors, but my experience has been that few projects get significant outside contributions (and few projects are welcoming of outside contributions, but that's a different problem).  That certainly seems to be the case here.  Of course, there could be many reasons for that.  Although I tried to make the code accessible, few people have the programming skills required to contribute.  And it's not like map compass generation is a problem of wide interest.  Also, my version of it might be poorly publicized or poorly executed.  But whatever the reasons, there was no interest in contributing to the code.

For another data point, we can look at Azgaar's fantasy map generation project which is obviously of broader interest.  Azgaar makes his code available and does a lot of work to create and support an active community of users.  Looking at his code statistics, it's clear that out of his thousands of users only a small handful have made any contribution to the code.

I often get emails or messages asking me to share the Dragons Abound code, and many of these messages claim to be interested in modifying or contributing to the code.  I made sure to bring the map compass experiment to the attention of several people who had made those sorts of requests; none of them responded or engaged with the code.

My conclusion is that there's virtually no software development benefit in sharing the code for this kind of project.  It has significant costs, and seems unlikely to provide any return on the investment.  If you have an interesting and well-crafted project, you'll likely get a fair number of people wanting access to the code, but it seems clear that almost all of these people want to use the code, not contribute to maintaining or improving it.  Which is not to say you shouldn't share your code or make it public, just don't do it expecting to find an engaged and contributing development community.

I've focused above on code contributions, but another possible benefit of the code sharing might be that blog readers get more out of postings that were paired with actual code.  But I don't think this was the case.  I don't have any hard statistics, but I get the sense that people engaged less with the code sharing postings.  (Certainly I didn't get any feedback praising the addition of code.)  I'd guess that most people prefer to read about the highlights and insights of the software development rather than the nitty-gritty details of the code itself.  And that's understandable.  It's a lot of work to read code and comprehend what it is doing.  Unless you're planning on modifying the code yourself, there may not be much to get out of that.

Overall I rate the map compass experiment a success.  The whole process of writing the blog and the code intertwined was new and I think I got something out of it.  I also enjoyed figuring out how to make the code public and accessible.  And it did bring some clarity to my thinking about code sharing.

And now onward to other things!

14 comments:

  1. Thanks for being open about it :-)

    ReplyDelete
  2. I stumbled across this series, and I did read the code. Mostly I was awed by your tenacity at deep diving into such a niche subject, and my amazement and wonder grew with each subsequent post. It made my nerdy heart sing with joy! The final product is fun the play with and I go there when I'm feeling down and need something to cheer me up. Sharing is caring, as they say, so thank you.

    ReplyDelete
    Replies
    1. Thanks very much for the kind comment. I'm happy that you got so much out of the writing!

      Delete
  3. The creative vs conservative thing reminds me that I used to make more creative generators and then I got into a situation where I had to make them conservative (shipping a product where I don't get to manually prune out the bad ones), and I guess I've been making them conservatively ever since! You reminded me that I should consider going back to the creative ones.

    ReplyDelete
    Replies
    1. Good point, I believe I'm too deep into conservative approach as well

      Delete
  4. I was very happy to see your open source experiment, but it seems like a lot of work! I followed along initially but I have to admit that compass roses aren't too interesting to me.

    What I'm usually looking for is that I want to read your blog post about the technique, and then *occasionally* I want to look at the source code to see details that I'm curious about but weren't described in the blog post. But that's a very different model than wanting to actually use or contribute to your project's code, or participating in an "open source community".

    I'd like to think Martin O'Leary was helped by being able to look at my voronoi map generator code, but I don't actually know if he looked at the code or only at the blog post.

    I am fairly pessimistic about getting open source contributions that are useful for my own projects. Other people's goals are not my own. I definitely don't want to manage a contributor community. So I share my map generators as open source but with a "toss it over the wall" approach. It's relatively low cost (other than having to include dependencies) and also low benefit (I don't expect or even want contributions). I do very little cleanup, I don't write blog posts about the code, I don't use branches, etc.

    I also tried some experiments in making reusable utility libraries, but it's just not my thing. It was a lot of work for little benefit.

    Whether open source or not, I think it would be fun if people other than you could *run* your generator :-)

    ReplyDelete
    Replies
    1. Thanks for the comments, Amit, insightful as always. I think you're right about the level of engagement with postings about other people's coding process: some high-level details about approaches, solutions and problems and only occasionally dipping down into code when there's some particularly interesting point.

      Delete
  5. Quite the opposite to Amit, I'm pretty interested in compass roses. But I have to admit I'm not really interested in contributing. ProgGen community is small and only a small portion of it follows the ProdGen subreddit. Meanwhile there are lots of people who could be potential users of the code if it's distributed as a service. For example, I can see how your Compass Rose generator can be easily integrated to the FMG as a third-party service (we can talk about it in details in you're interested in). That could give the tool an audience of real users instead of a developers coven.

    So I agree that sharing code is hard and lowly beneficial, but sharing the result as something usable is different.

    ReplyDelete
    Replies
    1. Azgaar, are there other good ProcGen communities outside of Reddit and Twitter? And you'd prefer to have something like the compass rose generator as a service rather than just be able to grab the code and integrate it into your FMG?

      Delete
    2. No, at least I don't know about them. That was the point – procGen community is tiny, but out creations can be really helpful for roleplayers, which is gigantic community.

      For the integration – I prefer it to be a part of our codebase if it's small enough (like a few thousand lines max). Service is also good. It can be some simple API like a have for Armoria (e.g. https://armoria.herokuapp.com/svg/500/example).

      But I value others' work and time, so a very basic integration via link or iframe is also an option.

      Delete
    3. There's also the procjam discord! https://discord.com/invite/MjRaWGZ

      I agree that sharing code is hard and low benefit, and sharing the result as something people can run would be appealing for a much wider audience than just the procgen community.

      Delete
  6. It's really interesting to read this. When I posted my code I was struck that while I got some really helpful feedback on what I was doing wrong from a coding language point of view, I got none at all about the actual techniques and algorithms and things that the coding was *about*. Perhaps this is a reflection on the niche nature of what we're coding about, or perhaps an unusually large proportion of the people interested in this kind of thing aren't coders themselves!

    ReplyDelete
    Replies
    1. I think you're right that overlap between (1) coders and (2) people interested in procgen maps, and (3) people interested enough to make substantive comments / contributions is a very small set! Basically just the four of us here :-)

      Delete
    2. Well, I'm happy to be among such exalted company!

      Delete