A Great Old-Timey Game-Programming Hack - <AUTHOR> http://blog.moertel.com/posts/2013-12-14-great-old-timey-game-programming-hack.html <comment><USER3> This reminded me of a game programming hack I did back in highschool. I had just started a school course on Pascal and decided to code a small game of snake, just for fun. I knew very little about actual programming, I was a real novice. The game was very simple, it was running in a windows console (cmd) without any graphics, the actual assets were ASCII art. The grid of the game was represented with asterisks and the snake was dots with a smiley face (one of those weird ASCII symbols nobody knows why it's there). Every game update I would redraw the whole grid, snake and the comma that was used to output the food.

The problem was that this was terribly slow, it flickered like crazy and it was unplayable. I was very sad because my game was working but unplayable for anybody so I tried to engineer a way to make it stop flickering. The solution came when I found out about a couple of functions in pascal that let you clear a specific character in the console at a specific X,Y coordinate and write another character that that coordinate. What I ended up doing was keep track of all the changes in the game for each frame (snake movements, food position) and just re-draw only the portions of screen that had changed.

This was great, no more flickering and the game was playable. (Nobody really played it because nobody cared but I was really proud of it).

Found out years later that this approach is pretty much what Carmack did in his old games: Adaptive Tile Refresh[1]

[1][https://en.wikipedia.org/wiki/Adaptive_tile_refresh](https://en.wikipedia.org/wiki/Adaptive_tile_refresh)

<comment><AUTHOR> I'm sorry, but believing you did in the highschool what Carmack managed to achieve on the PC in his early games is delusional.

What Carmack achieved (by using the hardware features of the graphic cards of that day) is properly described in the link you give: smooth side scrolling on the PC. The kind of scrolling seen on the consoles of that day, which had a hardware support, or in the famous [http://en.wikipedia.org/wiki/Super_Mario_Bros](http://en.wikipedia.org/wiki/Super_Mario_Bros) (a copy of which is the unreleased "Dangerous Dave in Copyright Infringement" made by Carmack). That has nothing to do with drawing only the changed characters with simple print at the given screen coordinates, what you did.

To achieve that, it used exactly hardware feature of changing the origin of the area in memory that is going to be picked up by the graphic chip to be presented on the screen. That changing was made in _one pixel increments._ Without it, no smooth scrolling. Second, he redraw the tiles, he didn't print the characters.

So no, that is absolutely not "pretty much what Carmack did in his old games." What you did at the end was done by absolutely every game at these times (using the commands of cursor movements to position the characters then printing them, in Turbo Pascal using gotoXY from the console library), what you started with (reprinting the whole screen just because) was simply as "pessimized" approach as it can be made at all. You didn't even optimize anything, you did what everybody did, you just started with the "pessimization." I'm old enough to remember. There is also at least somebody here who can provide a link to any computer magazine which printed such games in a few lines of code (at that time sources were made small enough to be printed in the magazines).

For the reference, at least the terminals in 1973 already had "Direct Cursor Addressing" \-- the technology behind the gotoxy you used:

[http://vt100.net/docs/vt05-rm/chapter3.html#S3.8](http://vt100.net/docs/vt05-rm/chapter3.html#S3.8)

(It was already standardized anyway!) That terminal had 1440 characters, all directly addressable, and the maximum communication speed was 2400 bps which gives 300 characters per second or almost 5 seconds to push the whole screen to it. If you moved for example 10 characters, each with a 5 byte sequence, you needed only 50 bytes, so you can change their position 6 times per second. Everybody at that time knew that stuff. It was slow enough to see.

<comment><USER3> I'm not sure where all the bitterness comes from but obviously I'm not comparing an amateurish attempt at optimizing a terminal-based snake game written in Pascal to the genius of Carmack, those are two entirely different things.

And yes, I did that while I was in highschool, which is still years after Carmack did his deed. It was around uh... 2005?

I thought I'd just share an interesting "hack" I did when I was a teenager which, to me, felt like a real genius trick to smooth gameplay. Back then my code was literally a lot of messy spaghetti goto hell, so you can understand how much of a novice I was.

I recommend re-reading what I said, I never claimed I "pretty much" did what Carmack did, just that the idea behind incremental upgrades was "pretty much" similar to Carmack's genius. No more, no less.

<comment><AUTHOR> Your words "this approach is pretty much what Carmack did in his old games."

Let me rephrase in less words, it is _absolutely not_ pretty much what Carmack did. You just "rediscovered" cursor positioning feature introduced eons ago on the character-based terminals. Carmack did something else and _with the bit- mapped screens_ using the specifics of the graphics adapters of that time. The tracking you try to refer to he did on the scrollable pixel addresses, you just did simple character prints for $deity sake!

For the explanation of my opinion, see my previous post.

<comment><USER3> From wikipedia[1]: "The technique is named for its other aspect, the tracking of moved graphical elements in order to minimize the amount of redrawing required in every frame."

That's all I did, really. Not pretending I did anything more complex than that, I didn't even have access to a framebuffer or anything... Let's say the "principle" was the same, the delivery far from it.

[1][https://en.wikipedia.org/wiki/Adaptive_tile_refresh](https://en.wikipedia.org/wiki/Adaptive_tile_refresh)

<comment><AUTHOR> So according to your logic, as you've read in your school book and then wrote in your notebook a^2 + b^2 = c^2 that is "the same principle" what Einstein did with discovering E = m c ^2 since it has ^2 and the letters. Impressive.

Your school book is the equivalent to the Turbo Pascal on-line help (or TP book if you used TP 3). The similarity of the formulas is the similarity of your implementation and Carmack's "being first." Having your post the top of HN discussion of one real hack makes me deeply sad as it obviously reflects there are some readers who support your view of "the same principle." Or just don't understand, in my view.

<comment><USER4> Not really. Dirty rects are dirty rects! And anybody familiar with coding for crappy systems that sported hardware scrolling would use the same technique, because your options are limited when the screen moves due to base address changing and yet you want in-memory sprites (i.e., bits copied into screen memory by software or hardware, rather than images drawn automatically at a particular position during the scan) to move independently while drawing nicely on top of the background. And for full-screen scrolling games it is usual for at least the player sprite to stay centred. BBC Micro examples from the 1980s would include JCB Digger, Uridium and Firetrack. I bet Atari ST and Amiga games did the same thing too; the principle extends obviously to multi buffering.

The cunning part of the Carmack games was presumably widening the screen - <USER2> don't think I ever saw this done on the BBC. But as a schoolboy in 1989/1990 I'd experimented with reducing the BBC's screen height by one character row (by tweaking R6) to avoid flicker when scrolling vertically. Same principle. It's a fairly obvious thing to do, once you've figured out what's going on.

I think one can come up with better evidence for John Carmack's uniquely amazing skills.

<comment><AUTHOR> You discuss Carmack's pixel scrolling and miss the fact that this guy here who claims he did "the same" just had to draw one character of the snake's head at the new position, overwriting the previous head with the "body" character. And the tail character with the "empty" character unless the snake eats something.

What in the world has that to do with Carmack's algorithm of updating Mario after one pixel hardware scroll (after which he has to redraw the "unmoving" part fully) and adding more background once he spends the hardware moves?

<comment><USER4> Same principle, as I see it, whether it's writing 1 byte, calling gotoxy/putch, or copying a whole bunch of bytes. Dirty rects! The insight is the same: you draw the things that have changed, and leave alone the things that stay the same.

</comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER5> >The challenge wasn't overwhelming complexity, as it is today. The challenge was cramming your ideas into machines so slow, so limited that most ideas didn't fit.

I like this line right here. It does seem like we've piled on abstraction after abstraction in these days. Sure this does make things easier, but I think things have gotten so complex that it's much harder to have a complete mental model of what your code is actually doing than in the simpler machines of the past.

<comment><USER6> There's totally a parallel between this and the video game music of Mario, Zelda and Final Fantasy- they could only play 2-3 notes at once, so they had to work with those constraints. The music couldn't be too complex, so every note had to go really, really far. The result? Extremely memorable tunes with catchy melodies. It was a matter of necessity.

<comment><USER7> The Mega Man games had amazing music too, but I think Metroid still stands out as one of the best examples of fantastic 8 bit music. Haunting!

<comment><USER8> Honestly I think a lot of this is nostalgia - I grew up with the c64, never had a NES. I enjoy chiptunes but none of the NES stuff really does much for me. I think you have to have had this stuff embedded into your brain by repeated play. I've listened to NES music and haven't had an urge to listen to it enough to learn and hum it, but I could totally hum the eerie opening theme to Parallax, the driving pseudo-Jarre of The Last V8, the electro-rock of Oxxonian, and more.

I'm not _entirely_ sure it's all nostalgia; the c64's sound chip was a bit more flexible than the NES's, and there was a real culture of musicians on the c64, so I may have just gotten used to a higher level of musicianship as a base.

</comment></comment></comment></comment><comment><USER9> Loved the story! Mostly because I lived this stuff, and I'm 25 years old :p. In my Electronic Engineering graduation we had three professors crazy about assembly and slow PCs (in fact, FPGAs and microcontrollers). I remember the nights I spent awake trying to make a Viterbi Encoder/Decoder fit into a tiny FPGA, cramming a complex temperature controller (while reading sensors, commanding motors, and handling the input/output) in an 8051, or programming a 128khz sound recorder in assembly on an (old as hell) ARM, while communicating to a PC, showing info on a LCD and doing all the filtering digitally (the only analog stuff we were allowed to use were an anti-aliasing filter and the input/output conforming circuits). Ah, the crazy filters we devised to use all the old ARM's juice.

I lost myself there, but my main point is: in electronics (embedded systems, mainly) all this beautiful joy of crazy optimizations is still alive :D

<comment><USER10> You had some really outstanding teachers. Congratulations.

</comment></comment><comment><USER11> This is a really neat article. One thing: the author falls victim to a common, unfortunate mistake in calculating the percentage gains: _...120 cycles. That's a 30-percent speed-up._ and then _...98 cycles. Compared to the original code, that's 60 percent faster._

The right way to calculate this figure is (t1 - t0)/t0, rather than the author's formula which seems to be (t1 - t0)/t1. For instance: (157 - 98)/98 = 60%, but the actual amount is (157 - 98)/157 = a 38% speed up. A heuristic: 60% of 157 will be much more than 60 (since 60% of 100 = 60), which means a 60% speed up would reduce the speed to below 97 cycles.

It gets even more misleading the more efficient it gets: _Adding up the cycles, the total was just 1689. I had shaved almost 1200 cycles off of my friend's code. That's a 70 percent speed-up!_ The author has 1200/1689 = 71%, but the correct numbers yield 1200/(1689+1200) = 42%.

Not that I don't think these are significant gains, but it's just misleading to label them like this. If you've removed less than half the cycles, there's no way you've seen a 70% speed up.

<comment><USER12> Thanks for your feedback. (Author here.)

By my calculations (which I'll machine-check now with Maxima), the 30% and 70% speed-up claims are sound. First, let's fire up Maxima:

        $ maxima
        Maxima 5.30.0 http://maxima.sourceforge.net
        using Lisp SBCL 1.1.8-2.fc19
        Distributed under the GNU Public License. See the file COPYING.
        Dedicated to the memory of William Schelter.
        The function bug_report() provides bug reporting information.

Now let's calculate how much faster we made the row-copy code by unrolling its loop:

        (%i1) orig_loop_speed:     (1*row) / (157*cycle)$
        (%i2) unrolled_loop_speed: (1*row) / (120*cycle)$
        (%i3) unrolling_speedup:   unrolled_loop_speed / orig_loop_speed,  numer;
        (%o3)                          1.308333333333333

In other words, the unrolled-loop speed is 1.3 times the original-loop speed. That's 30% faster, right?

Likewise, how much faster did shaving those 1200 cycles make the tile-copy code?

        (%i4) copy2_speed:        (1*tile) / (2893*cycle)$
        (%i5) copy3_speed:        (1*tile) / (1689*cycle)$
        (%i6) copy3_vs_2_speedup: copy3_speed / copy2_speed,  numer;
        (%o6)                          1.712847838957963

I'm willing to believe that I've screwed up here, but I can't see where. Can you show me?

Thanks for your help!

<comment><USER13> Your only "mistake" was to switch to a different measure when giving the percentages. Your calculations are actually fine, because you explicitly label them "speedup".

However, this can confuse a non-thorough reader because your previous measures are not about "speed"; they are about "cost" (cycles). The parent just did not realize the switch, and thought that you were claiming to have reduced "cost" (cycles) by 30%/70%, which wouldn't be true.

<comment><USER12> Thanks for this insight! I never would have seen it had you not told me. (I'm an engineering guy and switching between time-per-unit and units-per-time is so automatic for me that I didn't realize it wasn't automatic for everybody.)

I've updated the story to explain the calculation the first time it happens.

Thanks again!

</comment></comment></comment></comment><comment><USER14> We did this in our Sinclair Spectrum games to blit the backbuffer to the display memory. Interrupts were not a problem because if they occured during the PUSH (display memory), the corruption would be overwritten immediately when the blit continued, and if they occured during the POP, the backbuffer was going to be overwritten in its entirety the next frame.

However, we had to leave some space at the edge of backbuffer memory, because if there's an interrupt right at the beginning of the blit, the interrupt handler's stack frame could overflow outside of the backbuffer and corrupt other memory. That one was fun to find. [Edit]: I seem to have missed the second footnote where he already describes this issue.

</comment><comment><USER15> This is not unlike how 'fast' screen updates are done on the Apple IIGS. The fastest memory operations on the 6502 and 65816 involve the stack, so one ends up mapping the stack to the top of framebuffer RAM and pushing a lot of values onto it in an unrolled loop. The unrolled loop is itself rewritten by other code to provide the data for the next update.

Apple developer support themselves described this idea in Technote #70, [http://www.1000bit.it/support/manuali/apple/technotes/iigs/t...](http://www.1000bit.it/support/manuali/apple/technotes/iigs/tn.iigs.070.html)

<comment><USER16> That's even faster than the push-pop sequence that this describes.

</comment></comment><comment><USER17> Reminds me fondly of the time I was writing assembler for the ARM2/3... it had such a nice instruction set that made hand-writing assembler pleasant.

It had a "barrel shifter" that gave you free shifts of powers of two, so you could calculate screen byte offsets quickly:

      // offset = x + y * 320
      ADD R0, R1, R2, LSL #8
      ADD R0, R0, R2, LSL #5
      // = 2 cycles

It also had bulk loads and stores that made reading/writing RAM cheaper. The trick there was to spill as many registers as you possibly could, so that you could transfer as many words as possible per bulk load/store.

      LDMIA R10!, {R0-R9}
      STMIA R11!, {R0-R9}
      // Transfers 40 bytes from memory pointed to by R10 to memory pointed to by R11,
      // And updates both pointers to the new addresses,
      // And only takes (3+10)*2 = 26 cycles to do the lot.

Happy days...

<comment><USER18> If you ever feel like reliving a bit of your past the Game Boy Advance uses the ARMv3 instruction set. With an easily available flash cart you have a cool little portable system to develop on.

<comment><USER19> Nit: the GBA uses an ARM7TDMI that IIRC implements ARMv4T, which isn't a strict superset of ARMv3 (I think that's the first ARM that dropped the old crazy addressing). Still very fun to mess with.

<comment><USER18> Sorry about that! The ARM naming scheme confuses the hell out of me. I always mix up the processor generations and instruction sets.

</comment></comment></comment></comment><comment><USER20> Great story, thanks for this; it's a refreshing change from bitcoin and VC chatter.

</comment><comment><USER21> I have been searching _for at least 10 years_ for the term "involution": the set of functions where f(f(x)) = x. Now i have it. Thank you.

</comment><comment><USER22> I don't recall which of the Atari cart game did this (might've been Combat) rather than using space for storing sound effects the game would refer to its own code in memory for a random noise sound effect.

So true that back in the day much of a game programmers mental effort was spent on how to make big ideas fit inside small memory, anemic color palettes, and slow processors.

</comment><comment><USER23> Having just spent a good chunk of my weekend reliving my Commodore 64 assembly coding days, this was an excellent way to top it off!

<comment><USER24> I'm almost a bit disappointed I missed out on those days. Having to code like that probably would've taught me several useful lessons.

<comment><USER23> Well, you can still relive some of this by writing code to target an emulator or, more modern, an ARM chipset.

Also, the quality of tools nowadays is so much better than what you would've used back then. So much so, in fact, that these old machines could even become pretty useful as a learning tool since they're (relatively) simple and allow much easier testing and debugging since they can be used effectively as some kind of VM.

</comment></comment></comment><comment><USER25> Arcade video game programmers of that age have told me warstories of themselves. BitBlits? That stuff is still handled by the BIOS / OS. The real arcade programmers would code at the level of scan-lines manually. (IIRC, Pacman was programmed at this level).

Every 30th of a second, the screen would have to be refreshed. Arcade programmers would perfectly tweak the loops of their assembly programs such that the screen refresh would happen at the right timing. As the CRT scanline would enter "blanks", they would use the borrowed time to process heavier elements of the game. (ie: AIs in Pacman). The heaviest processing would occur on a full-VSync, because you are given more time... as the CRT laser recalibrates from the bottom right corner to the top left corner.

Of course, other games would control the laser perfectly. Asteroids IIRC had extremely sharp graphics because the entire program was not written with "scanlines" as a concept, but instead manually drew every line on the screen by manipulating the CRT laser manually.

Good times... good times...

<comment><USER26> Actually Pac-Man was part of the second generation of videogame hardware where everything was "tile" based. The hardware generator was given a small RAM map of the playfield and then it would pull shapes from ROM and put them on-screen in a grid pattern. Less reliance on scanline timing and more logic could be done asychronously from the beam. The Nintendo NES would follow this design architecture later.

The Pac-Man Dossier is a great reference for this kind of stuff:

[http://home.comcast.net/~jpittman2/pacman/pacmandossier.html](http://home.comcast.net/~jpittman2/pacman/pacmandossier.html)

<comment><USER25> Thanks for the correction. I must be thinking of games older than Pacman then...

IIRC, Kangaroo used the old scanlines system, but its release date is after Pacman. I guess everyone was still trying to figure out how to do scanlines correctly at that time... so it must be different from arcade-game to arcade game.

<comment><USER26> Every manufacturer brewed their own hardware in-house. Remember this was cutting edge stuff in the early 80s. Things like RAM-based frame buffers were also insanely expensive, so you got tricks like this instead. Some went tile- based, others used custom ASICs or PLCCs to accelerate graphics.

</comment></comment></comment></comment><comment><USER27> I'll join the chorus reminiscing about hacking for game performance.

In my case, it was on a Mac on a PowerPC CPU. It's a far cry from the limited resources of early personal computers, but this was at a time when 3D was hitting big time - the Playstation had just come out - and I was trying to get performance and effects like a GPU could provide. A hobbyist could get decent rasterization effects from a home-grown 3D engine, but I was working as far forward as I could. All that unrolled code, careful memory access, fixed-point math... I spent a lot of time hand-tuning stuff. It wasn't until I dug into a book on PowerPC architecture that I found some instructions that could perform an approximation of the math quickly, and suddenly I was seeing these beautiful, real-time, true-color, texture-mapped, shaded, transparent triangles floating across the screen at 30fps.

It was about that time that the first 3DFX boards started coming out for Macs, though, and that was the end of that era.

</comment><comment><USER28> Used to do a similar thing with old Archimedes games (the first computer to use an ARM chip, in 1988). The original ARM had 16 x 32 bit registers, and a single assembler command could write some or all of them to memory in one go. In practice you could use about 12 of the registers for graphics data (the others being program counters and stack pointers etc). Each pixel was 2 bytes, so with 12 registers you could do 1 row of 24 pixels - all in one instruction. Fetch some new data into the registers and write them again 24 times and you had a 24x24 sprite drawn very fast. To really use this technique you had to draw at word boundaries, thus the movement had to be 4 pixels per frame. But you could do a good full-screen scroll with this at around 12-15 fps (Archimedes could also do double-buffered screen memory so you draw one while displaying the other) and still plenty of time to do all the other work for each frame.

</comment><comment><USER29> Another possible way to get around interrupts overwriting your screen, would be to turn them off and update the audio after every line or two.

<comment><USER23> Depending on the DAC you need so many interrupts "every line or two" is already too slow. Not sure if this was the case on the Tandy, though.

<comment><AUTHOR> So it was Tandy Color Computer 3 (CoCo 3). Thanks royjacobs.

Wikipedia has one more interesting detail about CoCo 3:

[http://en.wikipedia.org/wiki/TRS-80_Color_Computer#Color_Com...](http://en.wikipedia.org/wiki/TRS-80_Color_Computer#Color_Computer_3_.281986.E2.80.931991.29)

"Previous versions of the CoCo ROM had been licensed from Microsoft, but by this time Microsoft was not interested in extending the code further.[citation needed] Instead, Microware provided extensions to Extended Color BASIC to support the new display modes. In order to not violate the spirit of the licensing agreement between Microsoft and Tandy, Microsoft's unmodified BASIC software was loaded in the CoCo 3's ROM. Upon startup, the ROM is copied to RAM and then patched by Microware's code."

</comment></comment></comment><comment><USER30> Thanks for sharing this. This is what Eugene Jarvis did to make Defender fast. It was a common tool in the toolbox for any clever game programmer for the 6809. I think it is awesome that Tom & buddy to experience the pleasure of its rediscovery.

</comment><comment><USER31> So, question: what sits in memory below the bottom of the framebuffer? It seems like if a sound interrupt occurs while drawing the lowest-address tile, you might corrupt something below there.

Edit: Oh! Just got to footnote 2. Thanks, author!

</comment><comment><USER32> I still remember a hack that I figured out on the Commodore 128 to speed up the 80 column display. I'm not aware of any program that actually made use of it (probably because the C128 and its 80 column display did not have a big enough user base to make it worthwhile to develop programs that needed speedy output).

The C128 had two separate video chips/ports, a C64 compatible chip showing a 40x25 character (320x200 pixel) display, and the "VDC"[1] showing 80x25 characters (640x200, or with interlacing, 640x400 or more), which was output on a separate connector. The VDC had a hideous way to change the display: it had its own video RAM, which the CPU couldn't access directly, instead the video chip had two internal registers (low and high byte) to store the address you wanted to access, and another register to read or write the value at that address. But that wasn't enough, the CPU couldn't access those VDC registers directly either, there was a _second_ indirection on top: the CPU could only access two 2nd-level registers, one in which to store the number of the 'real' register you wanted to access, then you had to poll until the VDC would indicate that it's ready to receive the new value, and you would save the new value for the hidden register in the other 2nd level register. (There's assemply on [1] describing that 2nd level.) Those two registers were the only way of interaction between the CPU and the 80 column display.

[1] [http://en.wikipedia.org/wiki/MOS_Technology_VDC](http://en.wikipedia.org/wiki/MOS_Technology_VDC)

This was extremely slow. Not only because of the amount of instructions, but the VDC would often be slow to issue the readyness flag, thus the CPU would be wasting cycles in a tight loop waiting for the OK.

Now my discovery was that the VDC didn't always react slowly, it had times when the readyness bit would be set on the next CPU cycle. Unsurprisingly, the quick reaction times were during the vertical blanking period (when the ray would travel to the top of the screen, and nothing was displayed). During that time, there wasn't even a need to poll for the VDC's readyness, you could simply feed values to the 2nd level interface as fast as the CPU would allow, without any verification. Thus if you would do your updates to the screen during the vertical screen blank, you would achieve a _lot_ more (more than a magnitude faster, IIRC), and the "impossibly slow" video would actually come into a speed range that might have made it interesting for some kinds of video games. Still too slow to do any real-time hires graphics, and the VDC didn't have any sprites, but it had powerful character based features and quite much internal RAM, plus blitting capabilities, so with enough creativity you might have been able to get away by changing the bitmaps representing selected characters to imitate sprites. And you could run the CPU in its 2 Mhz mode all the time (unlike when using the 40 column video, where you would have to turn it down to 1 Mhz to not interfere with the video chip accessing RAM in parallel, at least during that chip's non-screenblank periods.) My code probably looked something like:

            lda #$12       ; VDC Address High Byte register
            sta $d600      ; write to control register
    	lda #$10       ; address hi byte
            sta $d601      ; store
            ldx #$13       ; VDC Address Low Byte register
            ldy #$00       ; address lo byte
     loop
                                                                cycles
            stx $d600      ; select address low byte register   4
            sty $d601      ; update address low byte            4
            lda #$1f       ; VDC Data Register                  3 ?
            sta $d600                                           4
            lda base,y     ; load value from CPU RAM            4 ?
            sta $d601      ; store in VDC RAM                   4
            iny                                                 2
            bne loop       ; or do some loop unrolling          3 ?
            ..

(28 cycles per byte, at 2 Mhz, => about 300-400 bytes per frame. Although the C128 could remap the zero page, too (to any page?), and definitely relocate the stack to any page, thus there are a couple ways to optimize this. (Hm, was there also a mode that had the VDC auto-increment the address pointer? Thus pushing data to $d601 repeatedly would be all that was needed? I can't remember.))

How would you time your screen updates to the vertical blanking period? There was no way for the VDC to deliver interrupts. It did however have a register that returned the vertical ray position. Also, the C128 had a separate IC holding timers. Thus IIRC I wrote code to reprogram the timer on every frame with updated timing calculations, so that I got an interrupt right when the VDC would enter the vertical blanking area.

As I said, I'm not aware of any production level program that used this; perhaps some did, but at least the behaviour was not documented in the manuals I had.

The VDC felt even more like a waste after I discovered this. The only use I had for it was using some text editor. I wasn't up to writing big programs at the time, either.

PS. sorry if that was a bit long.

<comment><USER33> This is the kind of genius I come to this site for. Thank you.

</comment></comment><comment><USER34> There should be a website where this kind of articles are collected!

</comment><comment><USER35> I do love the lesson that is implicit here. At least for me. The game was basically playable and doing what it was supposed to do _before_ these interesting hacks were done.

Another interesting tidbit that should be obvious, but I miss a lot. The format of the graphics was fixed and not necessarily on the table for things that can be changed to make the code work. All too often it seems I let what I'm wanting to accomplish affect how I plan on storing the data I'm operating on.

</comment><comment><USER36> I love this post.

Today most of game programmers just ask for a bigger GPU.

<comment><USER37> If a programmer back then doing crazy assembler stuff to get barely acceptable performance were given the option to work on today's hardware and write code that is _portable across chips and operating systems_ , provided they never do any clever hacks - do you really think they'd refuse?

<comment><USER14> That comparison as stated is a bit too extreme. However, I once had an Amiga programming wizard refuse a job because he didn't want to write C/C++ code for Windows PCs. He went on to do his magic on PSX and GBAs. In more recent times, there's plenty of hardcore programmers who have had a blast as PS3 SPU specialists.

<comment><USER38> And similar fun probably keeps going on the latest consoles, considering they have massive GPU sharing memory with the CPU, the devices even support atomic operations between GPU and CPU.

Incidentally that reminded me. How does one get to these positions? As the API's are closed there is no real way for an outsider to learn the ropes.

<comment><USER14> > How does one get to these positions?

\- Deep understanding of low-level programming issues: assembly, architectures, caches, DMAs

\- Experience doing advanced stuff in available platforms like OpenGL, DirectX, Cuda/OpenCL, etc.

\- Fluency in Maths is not necessary for all low-level development, but will certainly be for physics and graphics work.

Check out places like [http://directtovideo.wordpress.com/](http://directtovideo.wordpress.com/), [http://www.iquilezles.org/www/index.htm](http://www.iquilezles.org/www/index.htm) and [http://fgiesen.wordpress.com/](http://fgiesen.wordpress.com/). If you can show you even understand what they are talking about, you have a foot in the door. The rest is hand-on experience. :)

<comment><USER38> I meant more that I haven't really seen any open positions anywhere about positions like that, so I've thought it's more about who you know than what you know. I might be wrong though. Regarding skillset I pretty much have all of those. I have mostly thought that particular set of skills is not _that_ much needed (compared to <nodejs/C#/java/whatnot>)

Thanks about those links. While I'm well acquainted with iquilezles the other two were new for me.

The first link was especially interesting as I'm quite interesting in OpenCL raytracing, so that will save me a lot of research time in the near future, especially about the data structure selection. Interestingly with OpenCL 2.0 and devices that have shared memory anything that is fast to build on CPU and slow/open area of research on GPU can be pretty much ignored as the bottleneck between the two devices do not exist anymore.

</comment></comment></comment></comment></comment></comment><comment><USER39> Did you guys see the top comment? TempleOS:

[http://www.templeos.org/TempleOS.html](http://www.templeos.org/TempleOS.html)

Some features:

64-bit ring-0-only single-address-map (identity) multitasking kernel

HolyC programming lanaguage interpreter

Praise God for binds using timer based random number generators

Create comics, hymns, poems as offerings to the Oracle

<comment><USER40> Terry is also a (hellbanned) regular on HN. [1] He is believed to have schizophrenia, and most of his comments come across as a bit ... "out there". But occasionally his skill at systems programming shines through, which is fairly sad considering how crippled by his mental illness he appears to be.

[1] [https://news.ycombinator.com/user?id=losethos](https://news.ycombinator.com/user?id=losethos)

</comment></comment><comment><USER41> What computer and game could this be? Looking at Wikipedia reveals that the Motorola 6809 was not used for many computers, and not any that I recognize as being very popular.

<comment><USER42> Oh .. just a few video arcade games you might have heard of .. Defender, Joust .. Juno First .. and so on .. so, actually _quite_ a few games machines use the 6809 cpu ..

<comment><USER41> Those are not computers.

<comment><USER42> Sir, I beg to differ. I personally know of two individuals who are regularly reprogramming their 6809-based arcade boards, freely, with new software.

So, I urge you to reconsider your opinion; I believe it may be wholly incorrect.

<comment><USER41> By that metric, an abacus is a computer. This is not a workable definition for the discussion at hand.

<comment><USER42> Sorry, but wut? We're talking about systems that utilize the 6809 processor. This CPU is a general-purpose processor, used in quite many video game machines. What does an abacus have to do with anything?

<comment><USER41> I notice you called them "games machines" and not "home computers" or even "computers". It seem to me that you knew very well what I was talking about, but choose to be obtuse.

<comment><USER42> I grew up in an era when in fact the most potent computing power I had access to, as a hacker/programmer, required 20c.

Alas, I realize not everyone thinks the way I do, but I consider among the worlds most functional 'computing experiences' occurred during the Arcade era, where, indeed, one could wonder at the .. sheer .. computing power .. being used to render sprites. With 256 colors.

So, at the risk of perhaps moving the goal-posts, let me just say that while the 6809 might've been a 'games console cpu', at the time, it was also used in a few .. relatively interesting .. micro's.

Anyone returning to that era, in their own way, contributes what they can. In my case, I consider the still-functioning Joust and Defender machines in my neighbourhood, at the very least, accessible through a repository ..

</comment></comment></comment></comment></comment></comment></comment></comment><comment><USER43> Great story! I grew up with this type of programming.

Brought back nice memories.

</comment><comment><USER44> >> each tile was 28 by 28 pixels.

Why not a power of 2 like 16 or 32?

<comment><USER45> Having worked on similar applications, I can tell you that it was likely a graphical choice. It's difficult to balance legibility with screen space. 32x32 probably put too few tiles on the screen, and 16x16 probably didn't let him get enough detail in.

<comment><USER4> Indeed. In practice it makes very little difference how wide the sprites are, provided they are some exact number of bytes. You end up multiplying the Y coordinate by the row stride but working from column to column will be controlled by some kind of counter so any value will be fine.

</comment></comment></comment><comment><USER46> I'm confused about something. After they've implemented their final solution that lets tiles become corrupted before they're overwritten, what happens to the sound? The sound is now being written to the screen, where it will be promptly overwritten by the copy tiles routine. Wouldn't that cause audio corruption? Or did playback of the sound complete before the interrupt returned?

<comment><USER32> Calling the interrupt routine to play a sound sample used the stack, hence wrote register contents (and return addresses upon subroutine calls within the handlers) onto the tile target. No problem, as while the interrupt routine was running, the normal program was stopped. After returning from the interrupt, the stack pointer would be reset to the original value, and the normal program would go on overwriting the locations that had just been used for the interrupt handler stack. Playing the audio would not be disturbed at all. (This assumes that the stack wraps around at the end. Actually, there was probably still image corruption happening, if the irq was triggered at the very end of the stack range. Except perhaps the stack size was 16bit?)

Edit: yes, the stack pointers were 16 bit ([http://en.wikipedia.org/wiki/Motorola_6809](http://en.wikipedia.org/wiki/Motorola_6809)).

<comment><USER12> You have a quick mind to spot that edge case! See footnote 2 of the article for how we handled it.

</comment></comment></comment><comment><USER47> Sounds similar to the scrolling 'hack' John Carmack used on Commander Keen.

</comment><comment><USER48> I love this kind of stuff. It's the kind of article that today makes me very interested in embedded linux and systems that supposedly don't have enough resources to do things that we've been doing for decades.

Brilliant blog post!

</comment><comment><USER49> Dragon 32 - the pride of Wales: [http://www.theregister.co.uk/2012/08/01/the_dragon_32_is_30_...](http://www.theregister.co.uk/2012/08/01/the_dragon_32_is_30_years_old/)

</comment><comment><USER50> Good read.</comment>


Kafka and Donuts, Docker on Windows, #MSIgnite, Databricks, Interesting Week 38: - <AUTHOR> http://www.nielsberglund.com/2018/09/23/interesting-stuff---week-38/ <comment><AUTHOR> A roundup of things I found interesting the week just gone by.</comment>


Google: We'll test hiding the full URL in Chrome 86 to combat phishing - <AUTHOR> https://www.zdnet.com/article/google-well-test-hiding-the-full-url-in-chrome-86-to-combat-phishing/ <comment><USER2> i wonder how we will combat eviltwin webpages?

</comment><comment><USER3> Please no.</comment>


My failed bootstrapped startup: a retrospective. - <AUTHOR> http://blog.beautifulsavings.com/post/10051412771/so-long-and-thanks-for-all-the-fish <comment><USER2> These kind of posts always leave me with a mix of inspiration and discouragement.

It is awesome to read about someone like you (local developer, similar learning style, beginner entrepreneur) who actually builds something. There is a lot to be proud of for just Doing Something - even if you fail. But at the same time, I feel like I would fall into the same pitfalls that you mentioned.

I am not looking forward to doing anything related to setting up an LLC, doing sales calls, etc. I like my job and don't want to quit. I know other developers but end up working on my own stuff alone in most cases.

Thanks for sharing Aaron - I'll have to try to make it out to the next Devs With Side Projects meetup.

</comment><comment><USER3> My story is just like your story except that each time something didn't work, I took a few days or weeks off and then tried another site. And another. And another. It took dozens of ideas until I found a business that worked for me.

Take the lessons you learned and start again. Sooner rather than later. You'll probably fail again too, but eventually you'll stumble upon something that clicks. The key is refusing to give up.

Perseverance is much more important than any idea, programming language, or system of doing things. People who get it all right on the first or second try aren't skilled entrepreneurs. They're just lucky.

</comment><comment><USER4> Sometimes, the best startups start when you are dissatisfied with your present job, have nothing else to lose, but are smart, and have a couple of ideas you think are really awesome and a game changer. Check out this TechCrunch article where one of the cofounders of DoubleClick, Kevin O'Connor talks about the attributes of an entrepreneur: [http://techcrunch.com/2011/08/19/founder- stories-kevin-oconn...](http://techcrunch.com/2011/08/19/founder-stories- kevin-oconnor-good-entrepreneur/)

He lists a few signs of a successful entrepreneur. A desire for control and the ability to challenge authority are near top of the list. A way to detect the second trait? "Have you told your boss to shove it?"

</comment><comment><USER5> Most of the time, if your startup is a side-project (IE: you have a full-time job), it won't be successful. Not to say that this is impossible.

I've found that when you are working full-time on something, your mind is in a different place. You can also move much faster.

<comment><USER6> I don't recommend anyone to quit a FT job unless startup is already generating cash flow and need more hours of your time to scale further. My last startup failed because we foolishly quit our jobs prematurely, it created pressure on us to generate income, we had to abandon bootstrapping, forced us to look for outside financing, wasted too much time trying to chase angels and VCs instead of focusing on business, made us quit 12 months before cloud backup (our target) took off.

Now, whenever someone tells me that such an such angel asking him to quit job to show commitment to startup, I tell him to tell angel to write a check for $X and then you will leave your job. Don't quit job if someone want to see that as your commitment to the cause.

<comment><USER5> Either the startup is generating cash or you have enough money in the bank to last you at least a year. A year and a half ago, the company I was working for went out of business and I was let go. I had 3 years of savings and I decided to go full-time with my side projects.

It's tough to juggle both because you have to switch your mind from one thing to another. Not only this, but if you are working full-time and working on your company in your free time, you have little time left over to just relax. This caused me to burn out a couple of times a year.

Another concern of mine was that the company I was working for would try to claim ownership over my projects if they ever became successful. Even though the code bases were completely different (and so were the industries), I never wanted to take that chance.

I suppose I could have just put everything out there and told my former employer what I was working on, but this would have caused lots of problems for me.

I'm in a better place now and I've accomplished more in a week than in a month when I was trying to do both. I am also in a good position because I don't have a wife or kids. I realize that not everyone can do this.

<comment><USER6> Only point I wanted to make was that quitting job is not a pre-requisite to having a successful startup, which you were implying. I used to hear that often and naively believed that to my own peril. I discourage others to do the same however amount of saving you may have unless you are at a stage where you never need to work for money.

<comment><USER5> "Only point I wanted to make was that quitting job is not a pre-requisite to having a successful startup, which you were implying. I used to hear that often and naively believed that to my own peril. I discourage others to do the same however amount of saving you may have unless you are at a stage where you never need to work for money."

If you don't have any money in the bank, then you shouldn't quit your job. However, I feel that it's better to quit your job after saving money than toil away for a much longer period of time trying to do both.

I suppose it also depends on your startup. If you are trying to start the next zany Twitter or Facebook app or your goal is to just get funding, then yeah, maybe a year of savings won't work...

<comment><USER7> I'm at a similar point. I have about one years worth of savings in the bank and could probably stretch it to two years if I sell some stocks. I'm also young so if I blow through that money I will recover.

A friend of mine had a great idea that we are going to work on and I just thought it's now or never. If I try to work and do this on the side, I don't really see myself putting in as much as I could and it would be a regret down the road.

The "To quit or not to quit" question isn't so black and white. Definitely don't quit if you are living paycheck-to-paycheck but if you have at least a year's worth of living expenses saved up, I think it's worth it to give it a shot.

Yes, some people build businesses while they are working full-time. Other people need the motivation or time of giving it their all. It's a case-by-case scenario.

<comment><USER8> Before you quit your job and plan to spend a year on your startup, _validate_ your asumptions. Will there be anyone who cares about your product once it's finished? Don't write one line of code until you really know the answer to that question.

<comment><USER7> Yes, we've talked to some people and believe they would be interested when it's ready. Obviously it's not a sure thing but I'm fairly confident this idea is something that is needed. It's a B2B app.

PS. I like your equity calc.

</comment></comment></comment></comment></comment></comment></comment></comment><comment><USER9> I really enjoyed reading your story. I had similar experiences with my side project as well.

In my case, I tried to take on the behemoth that is Intuit. I spent 2 years working on the same side project. In my third year, I decided to quit my job and focus on it fulltime. Six months into working on my startup I realized that I made the mistake of trying to pick a fight with Intuit since the product that I was building was too much for me to handle.

I decided to switch course and focus on niche products for the Mac App Store. Two months after my pivot, I was making a few thousand a month from my apps. I've since accepted fulltime employment and am continuing to work on my Mac Apps as they are still generating the same amount of money.

From this experience I learned its best to focus on a niche market if you are a one man band. I think your failure was because your focus was too wide. Perhaps for your next project, you should consider focusing on a niche market.

Good luck.

</comment><comment><USER10> I think starting anything in the coupon space is difficult as it's not about the technology, it's about the sales. Groupon has an extremely simple website...it is merely a platform to display the deals: their success is essentially totally driven by the massive sales force they have at work them.

I think that technology in this space will play a greater role in the future (mobile, targeting, etc.) but for now the winners are those who sign up the most businesses and the most consumers.

I don't think the author should give up on startups entirely; it sounds like they have indeed learnt some skills and can apply those to any number of future projects. At least they have worked out this space is not for them!

<comment><AUTHOR> Don't worry, I haven't given up. :) Well, I haven't given up for good... in the short term, I just can't swing work+fam+startup. For now I'll just keep working on side projects and see if any of them make any headway. ;)

</comment></comment><comment><USER11> I fought against the need to quit my job for over a year while I was working on startups on the side. It took an idea that I was wildly passionate about and a well-timed layoff to make me realize that being "all in" wasn't just a poker metaphor the already-successful used to look down on plebes like me.

That said, I'm stupidly well-placed to be working on my own idea, unpaid - I'm using the self-employment assistance program through my state's unemployment department to get UI checks without having to job hunt (I do, however, have to submit business plans and the like). I also have enough in the bank to cushion me when the government cheese runs out.

<comment><USER12> What state are you in?

<comment><USER11> Oregon. One of only a handful of states with self-employment assistance programs - the others are Delaware, Maine, Maryland, New Jersey, New York, and Pennsylvania, AFAIK.

</comment></comment></comment><comment><USER13> The long and sometimes lonely path of a start up... apologies as this maybe slightly off topic.

I keep seeing stories of start ups that are a huge success, launching or died.

Where are all those companies in between? Perhaps it's a combination of not being exciting to report on and founders being busy (both of which could be related to working hard).

Anyone know of place for those between launch and dead?

<comment><USER14> _Anyone know of place for those between launch and dead?_

In between "I'm shutting down because of lack of traction" and "I just got acquired for $20 million" I know a few people whose startups have become "lifestyle businesses". Though that term seems synonymous with failure on HN, for the people I know, it means being the boss, not having one, working from home (or Hawaii, Thailand, etc. for a few weeks at a time) instead of working in a cubicle. They're making anywhere from $150k to $240k per year, and will likely continue to earn that but not much more because the businesses don't scale easily, but they're doing what they love.

<comment><USER13> Do any of them have blogs or communities that they frequent? I would be interesting in hearing their perspective, thanks.

<comment><USER14> Shoot me an email at {my HN username} at gmail and I'll get you in touch with them

</comment></comment></comment></comment><comment><USER15> I've been writing a similar tale of my own - with a surprisingly similar name, as a matter of fact.

It's never easy to watch something you've poured so much work into fall apart like that, so my condolences on your loss

<http://lookingbackaretrospective.posterous.com>

</comment><comment><USER16> Best of luck on your next startup. I honestly think that in the end you just had to ask yourself if you were willing to spend the next 10 years of your life working on Beautiful Savings. If your answer is "no" then obviously, pouring more time and effort into that startup seems painful. There's no point iterating continuously on a solution for a problem that you're not dedicated to solving.

I think though once you find that idea that you're genuinely excited and passionate about, you'll find that failure only occurs when you decide to stop iterating. If a person has a solid idea and solid execution, I find it hard to believe that the end result will be graded an "F", more likely it'll be a C or D, unless you are very very unlucky. The idea is the that the next iterations bring it to an A or B.

</comment><comment><USER17> He writes:

 _"I dropped MongoDB in favor of using a relational database"_

I wonder what made him abandon a perfectly good datastore in favor of a SQL thing, because everybody knows that <http://www.mongodb-is-web-scale.com/> ;-)

<comment><AUTHOR> Lol, love that vid. :) Actually I happened to have gone down the same road as Rob Conery: [http://wekeroad.com/building-things/tekpub-a-six-pack-and- yo...](http://wekeroad.com/building-things/tekpub-a-six-pack-and-you)

Except in my case, since I was learning as I went, I didn't have time to figure out why the less-mature technologies weren't working just right. Or I'd look at a problem and see it solved nicely for relational DBs, but still needing some manual work to make it work with a NoSQL DB... and when it came down to actually getting stuff done, I hated writing code I didn't have to write.

That's actually an interesting thought: if you're trying to learn a technology, doing a startup is the _wrong_ thing to do. Because ultimately you are just wasting precious time on things that the business side doesn't care about. I hit that "conflict of interest" quite a bit through this process.

<comment><USER17> In my new sideproject I'm using MongoDB for the first time in my life. It works well and I haven't run into any obstacles yet; however, the data model for this webapp is trivially simple.

</comment></comment></comment><comment><USER18> Looks like he made the two classic mistake of a software guy with a startup (i made them too)

1\. Spend too much time futzing about with the technology. No one cares.

2\. Spend too much time futzing around with stuff you think a business needs to be a 'real' business.

</comment><comment><USER19> _"As a new player in the space we couldn't offer huge traffic or guaranteed results. So we had to give it away for free."_

How were you making money?

<comment><AUTHOR> I wasn't, unfortunately. This was self-funded. The idea was to give it away for a period of time ("3 months free! Buy today, pay later!!!!1! OMG!!") in order to crack the chicken-and-egg problem of content vs visitors.

<comment><USER19> It's the "we _had to_ give it a way for free" part that you should rethink. People like us are way to quick to price low/free because that's what _we'd_ pay for the service. Not at all what your target customers are willing to pay however.

"Double your price": <http://news.ycombinator.com/item?id=1639712>

</comment></comment></comment><comment><USER20> Your product needs two sides of customers: merchants want to reach more consumers and consumers want to get good deals. Breaking this chicken and egg issue creatively is probably the single most important thing you needed to do.

</comment><comment><USER21> I'm sorry, but I don't think you can say that "startup failed" if you haven't even quit your day job and focus 100% on your startup. Maybe you can say that investigation/discovery phase didn't yield desirable results.

</comment><comment><USER22> If all you building a Grouppon clone - then technology is the easy part.

</comment><comment><USER23> Please Note: This might seem critical but I'm just pointing out three problems i.e. lack of effort, lack of measuring effort and other statistics, lack of empathy with customers.

My argument would be that without at least 2 of these 3 the OP will keep running into problems and keep blaming extrinsic meaningless things.

 __ __ __ __ __ __ __ __ __ __*

Credit to the person (aaron?) for writing this. However, the lack of measured numbers is terrifying. And the disconnect with the customer perspective is just hard to fathom.

1) How much time did you spend on this? Over what period of time?

2) How much traffic did you get? How many people bought coupons? How many people went to other sites from your sites?

3) What amount of money did you spend? On what areas? What amount of money did you make? From what sources? ______________________*

You say that you didn't listen to your customers. My point would be that you didn't realize that you were making something FOR THEM and not for you.

You should consider thinking from your customers' perspective.

They really don't care about some of the things that you think are successes i.e. using hosted services and learning Ruby and the site being BEAUTIFUL because you think a site being beautiful is important to you personally.

Unless Indianapolis is 99% users of HackerNews.

 __ __ __ __ __ __ __ __ __ __ __ __ __ __*

You say that you were shocked that small business owners don't track things - yet you write this post without giving any figures. Which makes a great post meaningless because we don't know what 'You had no skin in the game' means.

Did you spend 40 hours a week after doing your day job? Did you do that for 3 full years? Did you put in $100K of your own savings?

 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __*

Finally, you went into a space where you had very few competitive advantages - not the first mover, not the best product, not the most money, not the most resources, no brand recognition.

If you had tried a niche within coupons or a new area you might well have seen much better results.

Also, you don't mention anywhere how much total time and effort you spent on this which makes it difficult to know whether your lessons are worthwhile or not.

If you spent 10 hours a week for 6 months - then obviously all your 'learning' is probably useless.

If you spent 40 hours a week for 2 years - then it's very valuable stuff.

which one is it?

<comment><USER24> How is time spent on something in any way correlated with how much he learned?

The whole idea of failing fast is that you don't need to invest pointless time after you have learned something is not going to work.

<comment><USER25> If you believe the premise and results of the '10000 hours to expert' research cited by Gladwell's "Outliers", then the obvious conclusion is that time invested is highly correlated with learning.

<comment><USER7> 10000 hours are needed to become a master or expert at something. An expert or master is in the top 1% of people who know that skill. But with learning something, anyone could reach the top 10% within 6 months. Dedicate to learning something for 6 months and you reach the top 10%. It doesn't take much time to go from nothing to a decent skill level. It does, however, take a lot of time to go from a decent level to a mastery level.

<comment><USER23> What diolpah said.

I'd rather learn from the experience of someone who became an absolute master. Because the lessons of absolute mastery apply across fields.

Who cares about the top 10%? The top 10% isn't worth wasting your time on. Especially if it means you spend 6 months each on 20 different areas and become top 10% in 20 areas.

Much better to find 1 or 2 areas you absolutely love and become top 1%.

Top 1% - Going to the Olympics. Top 10% - Impress your friends.

<comment><USER7> While I mostly agree with you there are plenty of times where it's worth it to be in the top 10% (or upper quadrant) but not the top 1%. These are things that are important to be good at but not worth the time to be excellent at. To say it's a waste of time to be in the top 10% is nonsense.

Take driving for example. When I started driving I enrolled in a driving course for several months. Now it's debatable that this course put me in the top 10% but it probably helped to put me above average. I have no ambition to be a race-car or stunt car driver so this is a great trade-off. I believe I'm a safer driver because of it.

Negotiating would be another example. It would make a lot of sense for a lot of people to take a negotiating course or read and practice it for a few months to get good at it in order to be able to negotiate their salary. The payoff of just a few months work could result in tens of thousands of dollars over your whole career. It wouldn't really be beneficial to spend 5-10 years getting your negotiating skills to the top 1% unless you wanted to actually do that for work.

Also the 10,000 hours really depends on if you are actually progressing or not. I think it's pretty debatable whether merely 10,000 hours of driving would put you in the top 1%. It's like the old joke that some people with 20 years of experience actually have one year of experience repeated 20 times.

Yes, you can't be great at everything but I think it's more valuable to great at one thing and good at a lot of things rather than just great at one or two things and mediocre at everything else.

Basically my point is, strive to be in the top 1% for what you want to earn money at or do with your life and then be in the top 10% for other things that either help you with that or benefit you in some way.</comment></comment></comment></comment></comment></comment>


Ask HN: startup launch - <AUTHOR>

Hello hackers. I just want to say that I have a beta test for free job ad advertising (for the moment). The main point of this site is not just to find jobs but to also try and find the right fit for your job or the right job you are looking for. When you get into the dashboard you'll be able to create 2 types a profile a job seekers profile or a company profile which ever type you are looking for. This is going to help people find the right fit for them. I even put follow request so you can keep up to date with any changes that have been going on with the company or job seeker profile. feel free to comment or mssg me on the site workzstation.com/musiic<p>www.workzstation.com <comment><USER2> Not sure if you're looking for feedback, but I'll share some since I looked at the site.

1) Unless having an account is a necessity for it to function, having a default account to log into would be nice so I can get an idea of what it is without having to sign-up (I'm guilty of not doing this before). I prefer to play around with the product to get an idea of what it is. Doesn't matter if it's unpolished, buggy, etc.

2) Check for spelling and grammar. "Workz makes landing jobs easier for you by helping our costumers putting themselves out there to be heard with a beautiful and elegant profile that describes who they are!" Personally, I have a hard time trusting anything with errors in spelling/grammar. Related to the first point: I would like to see an example of what a "beautiful and elegant profile" could look like.

3) Possible security issue. When I used the final link you provided, (workzstation.com/musiic) I saw what seemed to be the dashboard for a brief moment before being redirected to the login page.

4) Congrats on putting it out there :).

</comment><comment><USER3> Why not to tell people what they are signing up for in a few sentences on the front page?

Seems like the signup is broken.</comment>


A Preview of UX and UI Changes in Visual Studio 2019 - <AUTHOR> https://blogs.msdn.microsoft.com/visualstudio/2018/11/08/a-preview-of-ux-and-ui-changes-in-visual-studio-2019/ <comment><USER2> The link is dead. Anyone can tell what are the changes?</comment>


Ask HN: Shipping products to customers in Docker container - <AUTHOR> Have you ever delivered software products in the form of container?  How did you convince your customer? <comment><USER2> Don't do it. Customers hate it when you don't deliver clean operating system packages for the platform they run and they consider anything less unprofessional. I'm talking about enterprises and governmental institutions, not web companies.

Think of the consequences: while you might find "Docker" cool, by delivering your software as a "Docker" image, you are now forcing your would-be customers to come up with a "Docker" infrastructure just to be able to run your software. You would create an artificial dependency, because for OS packages they need neither additional software nor knowledge to install and run yours.

<comment><AUTHOR> Thanks for the warning. Really appreciate that.

> you are now forcing your would-be customers to come up with a "Docker" > infrastructure ...

The use of Docker in our scenario is more like a VM (system container) than buzzwords like micro-service/service mesh/container cluster (application container). (check [1] for more comparisons) ... so setting up an Docker infrastructure should be as easy as installing the docker package in one of their Linux box. At least that's our plan.

> You would create an artificial dependency ...

Actually we have been delivering the product, which contains many Linux native binaries/libraries, to many different customers for many years. They all have different working environments, ranging from RHEL 5.2 to the latest release of Ubuntu.

The solution we have been relying on is to build all the binaries as static- linked ones. To accomplish this, we have to maintain out-of-tree patches (some of the products are modified FOSS) to build scripts, which is a mess. So from our perspective, containerizing our product IS a direct way to eliminate the difficulty supporting varied environments and maintaining out-of-tree scripts at once.

We do add some dependency about docker, but we can provide a unified environment which removes all legacy dependencies. It should be a plus.

[1] [https://containerjournal.com/2016/07/25/system-containers- vs...](https://containerjournal.com/2016/07/25/system-containers-vs- application-containers-difference-matter/)

<comment><USER2> You should not need to build static libraries if you pick the oldest RHEL you can find among your customers: the GNU people claim that their libc is backwards-compatible, so your executables and libraries should work with the latest glibc.

Building static executables, while convenient, opens your customers to security risk: where rebuilding one shared object library would suffice, now they need entire new binaries. There is a reason why for example Solaris and illumos do not deliver static libraries. That's the reason why, to prevent one from doing exactly what you are doing for the reason I described.

</comment></comment></comment><comment><USER3> I'm thinking about doing this for my optionally self hosted SaaS. I plan to provide docker images, jar files and maybe some OS packages for common distros but I am still undecided on where to host them as the core jar files are closed source.

The ultimate selling point for doing this is to make it as easy as possible to get started using the product. Docker images on docker hub are the lowest friction method to run the app. (I target developers so assuming they know docker is OK)

</comment><comment><USER4> we at croit.io do deliver our software as a ready to run docker container. In the last 2 years, no problem at all. Customers easily understand it and we got no complaints so far. Best decision ever :)

<comment><AUTHOR> Cool! Just checked your page, it's interesting.

> ... no problem at all.

I'm glad to know that you and your customers have no problem with docker. But do they really have none? For example if you do have some close source, how did you convince customers that your image is secure/trust-worthy?

</comment></comment><comment><USER5> if you do it, consider releasing the image in a container format that can be executed by runtimes apart from docker (e.g. [https://developers.redhat.com/blog/2019/02/21/podman-and- bui...](https://developers.redhat.com/blog/2019/02/21/podman-and-buildah-for- docker-users) )

</comment><comment><USER6> All the time. Docker containers are such a great distribution format. More specifically, typically a Dockerfile itself or Dockerfile along with the image as opposed to just the image (but sometimes just the image).

And convince them of what exactly?

<comment><AUTHOR> Changing the way both sides used to, the benefit of changing from package to image release, little downsides, etc.

</comment></comment><comment><USER7> Would this be a good way to ship an opencv based product? I'm really at a loss how to let the client install it without a lot of technical steps.

<comment><USER8> For a native application, the easiest way I've found is to statically link OpenCV. If you're using vcpkg to build your dependencies then OpenCV is already statically linked in Linux (I assume that's what you're using if you're considering Docker) and on Windows it's just a matter of choosing the static triplet.

</comment></comment><comment><USER9> you might want to create a private registry within the client prem, and export/import the container.</comment>


Verizon's video app gets special data privileges - <AUTHOR> http://www.theverge.com/2016/2/5/10924268/verizon-go90-net-neutrality <comment><USER2> Doesn't excluding some services from a data cap make a lie out of having data caps to ease congestion, or to penalize "data hogs"?

For example, couldn't you just run Verizon's video app 24x7, and consume much more than your allotment, and not pay for the amount over your cap? Is Verizon prepared for this to happen? In how many cases?

So, data caps, and "bandwidth amounts" are just a way to wring money out of people, without some kind of consumer revolt, right?

Or is it that Verizon's bytes are smaller or more slippery than Netflix' bytes?

<comment><USER3> Not sure how this can be levelled at the congestion argument. Presumably Verizon's video service is running from their data centres over their internal pipes, rather than external networks where bandwidth is considerably more expensive and probably more limited.

Anti-competitive, sure, but I think that's about it.

I've always felt conflicted about this here in Australia where different ISPs have been setting up peering agreements to achieve similar situations for years. It works out better for the customers who get the unmetered service but at the expense of competition.

<comment><USER2> I live in Denver, Colorado. It looks like Hulu has servers located in Highlands Ranch, Colorado, right on the Centurylink network. Actually, they're Akamai servers, but still. Hulu has servers right next to a VPS in Los Angeles I have access to. Google appears to do the same, without Akamai. Your anti- congestion argument fails. It appears that large content providers co-locate servers on lots of networks.

So apparently Verizon's bytes _are_ slippery or smaller than other people's bytes. Maybe they use smaller bits or something?

</comment></comment></comment><comment><USER4> It shouldn't even be necessary to bring in net neutrality. This should fail on anti-competitive grounds alone.

</comment><comment><USER5> 1GB for $30? Are you joking me? Even we Germans, with 20x the data pricing of mainstream Europe, don't pay this much.

<comment><USER6> It is much, much, much more expensive to deploy cellular infrastructure in the US than anywhere in Europe. The US is massive, and cities have much greater distances between them than in Europe.

The carriers here can't price based on where you live, because people travel (and could easily fudge their addresses). So what happens is the people who live in cities end up subsidizing the infrastructure for people who live in suburban or rural areas.

We do have smaller carriers (T-Mobile and Sprint) that have much less coverage in non-urban areas, and those carriers are much cheaper. Google actually combines those two carriers into Project Fi, which costs much less than $30/GB (I think it's $10).

<comment><USER7> People per km^2:

Europe: 32 (edit: wrong)

US: 35

<comment><USER8> Not sure where you get that number for Europe. According to Wikipedia [1] it has a population density of about 73/km^2. European Russia also brings that number down a bit because it has a population density comparable to the US.

[1] [https://en.wikipedia.org/wiki/Europe](https://en.wikipedia.org/wiki/Europe)

<comment><USER7> Oh my mistake, I just googled it and didn't read the page:

[https://en.wikipedia.org/wiki/Area_and_population_of_Europea...](https://en.wikipedia.org/wiki/Area_and_population_of_European_countries)

Seems they included all of Russia too.

<comment><USER8> I think the figures for Russia specifically are for the whole country. But I read the population density for Europe as a whole including only European Russia. (Including all of Russia in the total would skew the result enormously as Asian Russia is bigger than all of Europe and only has a population density of about 3/km^2--and probably has pretty spotty cell phone reception:-).)

</comment></comment></comment></comment></comment></comment><comment><USER9> I wonder if they are just playing the waiting game, where for the average joe would get upset that they are missing out on this "free" video. They would then retort to saying that net neutrality is the issue at hand, and that it should be removed to allow for free lanes and paid lanes aka the issue we had at hand in the first place.

</comment><comment><USER10> These ISPs still simply have far too much power. The consumer is the only one that suffers from their unapologetic greed.</comment>


A surprising Python quirk - <AUTHOR> https://www.willmcgugan.com/blog/tech/post/strings-hiding-in-plain-sight/ <comment><USER2> Nothing surprising about this if you know grade school math. Nor is it really about Python at all.

The empty set is a subset of every set.

<comment><AUTHOR> Are strings sets?

<comment><USER2> Analogously, the empty net is a subnet of every net, the empty sequence is a subsequence of every sequence etc etc.

Also, [p implies q] is vacuously true if p is false.

Strings are maps from nonnegative integers to the space of characters. You can think of them as sets of ordered pairs or sequences.</comment></comment></comment>


Microsoft Admits Humans Listen to Skype and Cortana in Privacy Policy Update - <AUTHOR> https://www.vice.com/en_us/article/qvgpkv/microsoft-updates-privacy-policy-admits-humans-listen-to-cortana-skype <comment><USER2> Skype and Win10 is forced on us in large corps. Does this give MS the ability to now spy on people in these companies and gain information they would otherwise not have?

Another product to add to the blacklist.

</comment><comment><USER3> Does anyone remember when Skype wasn't a hot mess of wiretaps and centralized servers? At this point I'd trust Telegram and their wacky homegrown encryption more than Skype.</comment>


InfoWorld: Things Never To Do With A Relational Database   - <AUTHOR> http://osintegrators.com/opensoftwareintegrators%7C10thingsnevertodowitharelationaldatabase

<comment><USER2> Meh, maybe at scale. I'd say you'd be better off bunging everything in your db at first, and then extracting bits into more specialised data stores _based on testing and real-world performance data_.

To take one example from there - storing images in your db - this might actually be fine if you have a cache in front of your app servers, since your db only takes the hit once and then nginx/varnish serves the request after that.

Doing replication, versioning and backup for postgresql across a bunch of app servers is fairly straightforward. If all of a sudden you're doing it for postgresql AND mongodb AND lucene - and keeping all those backups in sync with each other - it gets a lot harder, at least without downtime.

Nosql, lucene etc are great tools, but often they're premature optimization. Make it work first using the simplest tools you have, then add complexity to improve performance only where and when required.

<comment><USER3> First off, if you're writing granny's addressbook it doesn't matter what you use. RDBMS, NoSQL, filesystem, it will work, who cares. I assume that this is at scale. It is a perspective of bill rates I guess :-) Not many grannies hire me to write addressbook apps :-)

Secondly, prototyping your straight JQuery/HTML to MongoDB or Couchbase 2.0 is SIMPLER than to the RDBMS where you must do XML transform first.

Search in RDBMS with ORs and LIKEs is hard and not a good idea for the RDBMS or your middle tier or your user (reduced capabilities with more complexity).

Storing images in the DB vs say a clustered FS makes everything from replication to performance to scalability. Get a few TB of BLOBs and tell me this is a good idea.

</comment></comment><comment><USER4> Very nice. I laughed to myself over "Search", remembering an absurdly complicated query I once wrote to do a search against an Oracle table.

Ending up with a dynamically generated query which got really long depending on how many spaces you entered... smh</comment>


Peer Review Checklist for Embedded Software - <AUTHOR> https://www.linkedin.com/pulse/peer-review-checklist-embedded-software-philip-koopman/?trackingId=0cL5qScaDjJaVT16BWfklA%3D%3D <comment><USER2> I know this is (becoming) an (even more) niche industry, but does anyone know of add-ons, plugins, or dedicated supplemental tools for more mainstream development tools (GitLab, Jira, etc) that caters for embedded development?</comment>