-
Notifications
You must be signed in to change notification settings - Fork 34
/
index.html
315 lines (272 loc) · 17.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
<!doctype html>
<html lang='en' class='darkmode'>
<head>
<meta charset='utf-8' name='viewport' content='width=device-width, initial-scale=1.0'>
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap" rel="stylesheet">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="manifest" href="site.webmanifest">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-41788989-5"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-41788989-5');
</script>
<title>DevShop</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<span id='money' class='metrics hidden' title='cash on hand'>💲100</span>
<span id='rate' class='metrics hidden' title='revenue rate' class='hidden'>(💲0/min,0📍/min)</span>
<span id='xp' class='metrics hidden' title='eXperience Points'>0/50🥓</span>
<span id='level' class='metrics hidden' title='Level'>1🥑</span>
<div id='loadscreen' class='hidden'>
<h1>LOADING...</h1>
<p>This <em>loading screen</em> will soon let you choose a saved game to play.</p>
<p>Oh, try <a href='https://NimbleText.com/live/' target='_blank'>NimbleText</a> I guess.</p>
<div id='loadslots'>
...slots here
</div>
<div class='button' id='exitload' onclick='exitloadmenu();' tabindex='0' role='button' >🏠 exit load</div>
</div>
<div id='startscreen'>
<h1>DevShop</h1>
<div class='button pulse' id='start' onclick='go();' tabindex='0' role='button' >🌟 start</div>
<div class='button hidden' id='loadmenu' onclick='loadmenu();' tabindex='0' role='button' >💾 load</div>
<!--<div class='button' id='about' onclick='about();' tabindex='0' role='button' >🥓 about</div>-->
<div class='button hidden' id='timechallenge' onclick='timechallenge();' tabindex='0' role='button' >⏳ time challenge</div>
<h2 class='twop'>Mailing List</h2>
<form action="https://secretGeek.us4.list-manage.com/subscribe/post?u=2c8d4a2f270735de4d2cf3845&id=64ebe920c2" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
<input type="email" value="" name="EMAIL" class="xemail" id="mce-EMAIL" placeholder="[email protected]" required>
<div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_2c8d4a2f270735de4d2cf3845_64ebe920c2" tabindex="-1" value=""></div>
<input type="submit" value="💌 join mailing list" name="subscribe" id="mc-embedded-subscribe" class="button joinemail">
<a href='#privacy' onclick='visitPrivacy();return false;'>privacy policy</a>
</form>
</div>
<div id='help' style='clear:left' class='hidden'>
<h1>DevShop</h1>
<div class='pp'>
<br />
<div id='closeHelp' class='button' onclick='leaveHelp();' tabindex='0' role='button'><span class='icon'>🥓</span> Go Back</div>
<br />
<br />
<h2 class='twop'>Help 😱</h2>
<p><strong>Getting Started</strong></p>
<ul>
<li>click "🌟 start"</li>
<li>click "🎁 find project ($100)"</li>
<li>Select on the newly created project in the <code>Inbox</code> column of the kanban board.</li>
<li>Select the "🤔 Founder". (In the animated version this would cause the Founder to walk to the board, grab the card, take it back to their desk, work on it, create a bunch of story cards, and take them back to the board, putting them in the <code>backlog</code> column.)</li>
<li>Once the story cards are in the <code>backlog</code> column, click a card to select it.</li>
<li>Select the "🤔 Founder" again. This causes the Founder to begin developing the card. (In the animated version, they would walk over, get the card, take it back to their desk, swear a lot, etc.)</li>
<li>The story card eventually ends up in the <code>Test</code> column. Now the card needs to be tested.</li>
<li>The founder is capable of developing, testing, and acting as a BA. They don't do any of these things <em>particularly well...</em></li>
<li>Select the card in the <code>test</code> column, then select the Founder, so it can be tested.</li>
<li>If it passes testing it is done... and you make money 💲. (It's possible a bug 🐛 is found during testing... or if the bug is missed by the tester, the customer can find the bug 🐞 once they receive the card.)</li>
<li>when the project is completed you get a completion bonus 💲.</li>
<li>And you can begin another project...</li>
</ul>
<p>Repeat this until you have enough money to buy a dev or a tester or a ba.</p>
<p><strong>Features include:</strong></p>
<ul>
<li>upskilling people 📕 📗</li>
<li>training people to increase their efficiency</li>
<li>giving them 'initiative' so they can sometimes grab cards for themselves.</li>
<li>☕ coffee and donuts 🍩</li>
<li>🐶 dogs and cats 😸</li>
<li>inflation. (i.e. things will cost more and be higher stakes as the game progresses.)</li>
<li>(People will get faster as you increase their skills, but jobs will be bigger... thus creating a steady state, a hedonic treadmill, a red queen's race 👑.)</li>
</ul>
<div id='closeHelp2' class='button' onclick='leaveHelp();' tabindex='0' role='button'><span class='icon'>🥓</span> Go Back</div>
</div><!-- .pp -->
</div>
<div id='about' style='clear:left' class='hidden'>
<h1>DevShop</h1>
<br />
<div id='closeAbout' class='button' onclick='leaveAbout();' tabindex='0' role='button'><span class='icon'>🥓</span> Go Back</div>
<br />
<br />
<div class='pp'>
<h2 class='twop'>About 🌆</h2>
<p><strong>Lessons! Everybody loves 'Lessons'</strong></p>
<p>If you consider DevShop as a tutorial on Kanban or Lean, there are some lessons you can learn by playing this game. These include the following:</p>
<ul>
<li>If work took no time to complete, you would only need 1 worker.</li>
<li>The earlier in the process a bug is found and fixed, the cheaper it is to rectify.</li>
<li>Bugs should be removed before they get to the customer.</li>
<li>Work should flow left to right.</li>
<li>You need higher proportions of workers for steps that take longer (e.g. development in this game)</li>
<li>The smaller the stories the better. They are less likely to have bugs, and faster to work with.</li>
<li>Multi-skilled workers are helpful for alleviating bottlenecks.</li>
<li>In a system where bugs and irregular work happen, bottlenecks can appear anywhere.</li>
<li>Throughput is a more useful measure than idle time.</li>
<li>Good teams are self-organizing, and this requires <em>initiative</em>.</li>
<li>A newbie thinks "I wish I could hire a manager to assign the tasks automatically" -- a wise person thinks "I wish the workers had enough initiative to select the tasks for themselves."</li>
<li>The system needs to have some slack in it, or there will be no way to respond to bottlenecks.</li>
<li>A founder, in the early days, needs to be able to do <em>anything</em>. Later employees can be increasingly specialised.</li>
<li>To state the above more generally: in a small company, or when work is volatile or sporadic, generalists are very valuable (even if their skill levels are not very high). In a larger company, or when work is more predictable, certain specialists are very valuable (and busy).</li>
<li>Resource levels need to be appropriately balanced.</li>
<li>Given a choice between doing something well or doing it quickly, it's better to do it well. It saves time soon enough.</li>
<li>People can only work on one thing at a time. If they worked on more than one thing at a time, it would decrease throughput. Multi-tasking is a waste of time. (But multi-skilling is not!)</li>
<li>A functioning and growing business can afford to pay a <em>lot</em> for good coffee ☕.</li>
</ul>
<h2 class='twop' id="non-lessons">Non-lessons</h2>
<p>There are many features of the real world, and of workplaces, that are not modelled in this game.</p>
<blockquote>
<p>"All models are wrong, some models are useful."</p>
</blockquote>
<p>In the real world:</p>
<ul>
<li>not all bugs are so easily dealt with: a single bug can do <em>unlimited</em> damage. That's a vital feature of real bugs, but isn't modelled in the game.</li>
<li>workers are not machines. They have good days and bad days, they have real lives. All of this is abstracted away.</li>
<li>customers don't pay immediately, sometimes they don't pay at all, <em>even when you've done good work</em>. Life isn't fair like that.</li>
<li>you have to pay workers after you hire them. Recurring paychecks aren't modelled in the game because they're not the problem I'm trying to demonstrate. But this isn't a sufficient answer to use in the real world.</li>
<li>skill levels are not a simple ladder, "dev skill == 7". They would be better modelled as a bifurcating directed acyclic graph, where every node represents a different atom of skill or knowledge. But there's no emoji for that currently.</li>
<li>before you hire a person, you don't accurately know their skill level. Often you don't know afterward either.</li>
<li>training takes time and it doesn't have a consistent outcome.</li>
<li>sometimes workers leave.</li>
<li>projects never really finish. If they went well there will be ongoing support and changes, indefinitely. If they went badly, the lawsuits can also drag on.</li>
<li>a situation where "any developer can develop any card" is not achievable. But you can take steps to move in that direction.</li>
<li>procurement of goods in the enterprise is not as simple as clicking a "buy" button.</li>
<li>workers spend non-zero amounts of their time in meetings, not shown in this game.</li>
<li>some related practices I find useful are Daily Standups, Retrospectives, Project Pre-Mortems and Code-reviews. There was no way to integrate these into the game without disturbing the flow.</li>
<li>context-switching takes time and effort.</li>
<li>some projects are not worth doing at all.</li>
<li>some bugs are not worth fixing at all.</li>
<li>some bugs are not bugs.</li>
</ul>
<p>Regarding the risk of skilled employees leaving, I love this:</p>
<blockquote>
<p>"What if we train them and they leave? <br />
What if we don't train them and they stay?"</p>
</blockquote>
<div id='closeAbout2' class='button' onclick='leaveAbout();' tabindex='0' role='button'><span class='icon'>🥓</span> Go Back</div>
</div><!-- .pp -->
</div>
<div id='privacy' style='clear:left' class='hidden'>
<h1>DevShop</h1>
<br />
<div id='closePrivacy' class='button' onclick='leavePrivacy();' tabindex='0' role='button'><span class='icon'>🥓</span> Go Back</div>
<br />
<br />
<div class='pp'>
<h2 class='twop'>Privacy Policy 🔏</h2>
<h3>(Well isn't this fun.)</h3>
<p><em>This policy was last updated 2019-12-04</em></p>
<p>NimbleThing Pty Ltd ("us", "we", or "our") operates https://DevShop.SecretGeek.net (the
"Site"). This page informs you of our policies regarding the collection, use and disclosure of
Personal Information we receive from users of the Site.</p>
<p>We use your Personal Information only for providing and improving the Site. By using the Site, you
agree to the collection and use of information in accordance with this policy.</p>
<h2 class='twop'>Information Collection And Use 💌</h2>
<p>While using our Site, we may ask you to provide us with certain personally identifiable information
that can be used to contact or identify you. Personally identifiable information may include, but is not
limited to your name ("Personal Information").</p>
<h2 class='twop'>Log Data 🤷♂️</h2>
<p>Like many site operators, we collect information that your browser sends whenever you visit our Site
("Log Data").</p>
<p>This Log Data may include information such as your computer's Internet Protocol ("IP") address,
browser type, browser version, the pages of our Site that you visit, the time and date of your visit,
the time spent on those pages and other statistics.</p>
<p>In addition, we use Google Analytics to collect, monitor and
analyze traffic to the Site. Please refer to Googles terms of service for further details: https://policies.google.com/privacy?hl=en-US</p>
<h2 class='twop'>Communications 📣</h2>
<p>We may use your Personal Information to contact you with newsletters, educational sequences of email, marketing or promotional
materials and other information related to the Site.</p>
<p>Some emails are transactional in nature and do not include unsubscribe instructions. For example, if you purchase a license, you will receive a confirmation of license details via email: this email is transactional and does not include an unsubscribe link. Similarly, password reset or security emails are examples of transactional emails.</p>
<p>All non-transactional emails from the Site will include a link you can use to unsubscribe from further emails. Additionally, you can contact us to request that you be removed from any future communication.</p>
<h2 class='twop'>Cookies 🍪</h2>
<p>And in this case when we say "Cookies" we don't mean delicious cooked biscuits. By "Cookies" we mean files with small amount of data, which may include an anonymous unique identifier.
Cookies are sent to your browser from a web site and stored on your computer's hard drive.
Like many sites, we use "cookies" to collect information. You can instruct your browser to refuse all
cookies or to indicate when a cookie is being sent. However, if you do not accept cookies, you may
not be able to use some portions of our Site.</p>
<h2 class='twop'>Security 🕵️♀️</h2>
<p>The security of your Personal Information is important to us, but remember that no method of
transmission over the Internet, or method of electronic storage, is 100% secure. While we strive to
use commercially acceptable means to protect your Personal Information, we cannot guarantee its
absolute security.</p>
<h2 class='twop'>Changes To This Privacy Policy 🤹♀️</h2>
<p>This Privacy Policy is effective as of 2019-12-04 and will remain in effect except with respect to any
changes in its provisions in the future, which will be in effect immediately after being posted on this
page.</p>
<p>We reserve the right to update or change our Privacy Policy at any time and you should check this
Privacy Policy periodically. Your continued use of the Service after we post any modifications to the
Privacy Policy on this page will constitute your acknowledgment of the modifications and your
consent to abide and be bound by the modified Privacy Policy.</p>
<p>If we make any material changes to this Privacy Policy, we will notify you either through the email
address you have provided us, or by placing a prominent notice on our website.</p>
<h2 class='twop'>Contact Us 💌</h2>
<p>If you have any questions about this Privacy Policy, please contact us. (We can be reached at "Support<span class="wtf">omit this
</span>@<span class="wtf">
omit this </span>NimbleText.com")</p>
<div id='closePrivacy' class='button' onclick='leavePrivacy();' tabindex='0' role='button'><span class='icon'>🥓</span> Go Back</div>
</div> <!-- .pp -->
</div>
<div id='office' style='clear:left' class='hidden'>
<h1>DevShop</h1>
<div id='buttons'>
<div id='getLead' class='button hidden' onclick='getNewLead();' title='Advertise and find a project to do!' tabindex='0' role='button'><span class='icon'>🎁</span> find project (💲100)</div>
<div id='getdev' class='button getPerson hidden dev' onclick='getNewPerson("dev");' tabindex='0' role='button'><span class='icon'>💻</span>hire dev (💲300)</div>
<div id='gettest' class='button getPerson hidden test' onclick='getNewPerson("test");' tabindex='0' role='button'><span class='icon'>🔬</span>hire tester (💲300)</div>
<div id='getba' class='button getPerson hidden ba' onclick='getNewPerson("ba");' tabindex='0' role='button'><span class='icon'>🗣</span>hire BA (💲300)</div>
<div class='button visitStore hidden' onclick='visitStore();' tabindex='0' role='button'><span class='icon'>🛍</span>visit store</div>
</div>
<table id='kanbanboard'>
<thead>
<tr>
<th title='[1]'>Inbox</th>
<th title='[2]'>Backlog</th>
<th>Dev</th>
<th title='[4]'>Test</th>
<th>Done</th>
</tr>
</thead>
<tbody>
<tr>
<td id='ba'>
<div class='inner'>
<span class='count' data-count='0'>0</span>
</div>
</td>
<td id='dev'>
<div class='inner'>
<span class='count' data-count='0'>0</span>
</div>
</td>
<td id='dev0'>
<div class='inner'>
<span class='count' data-count='0'>0</span>
</div>
</td>
<td id='test'>
<div class='inner'>
<span class='count' data-count='0'>0</span>
</div>
</td>
<td id='done'>
<div class='inner'>
</div>
</td>
</tr>
</tbody>
</table>
<div id='people'>
</div>
</div>
<div id='store' class='hidden'>
<h1>DevStore<span class='icon'>🛍</span></h1>
<div id='closeStore' class='button' onclick='leaveStore();' tabindex='0' role='button'><span class='icon'>🏢</span> leave store</div>
<div id='items'>ITEMS for SALE</div>
</div>
<span id='message'>Press '<span class='emojicon'>🌟</span> start' to begin.</span>
<span id='storeMessage' class='hidden'>⭐ Welcome to the DevStore ⭐</span>
<a id='aboutLink' href='#about' onclick='visitAbout();return false;' style='float:left;left:0'>about</a>
<a id='helpLink' href='#help' onclick='visitHelp();return false'>help</a>
<div id='debug' class='hidden' style='clear:both'></div>
</body>
<script src='script.js?3' type="text/javascript"></script>
</html>