Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

ENIGMA T HE UNBRE A KABLE D 5 W HOSE BRE A KING : W ON WORLD WAR T I SN CUYRB S JCNER V 5 O PLKI ODU W RCNS : Z AD SDERT STT M PYMSPQ it's been a long day, good day but long, so if you're able, please stand up for a second we're going to do a little stretch, get some blood fl owing, a few endorphins pumping diving into the pool

Slide 4

Slide 4 text

a j i (me ) hi everybody my name is Aji

Slide 5

Slide 5 text

t h o u g h t b o t I work at a place called thoughtbot

Slide 6

Slide 6 text

You may have learned in the 1930s and 40s, there was a war Involving many nations and peoples across the globe so many in fact, they called it a "World War" the second of its kind

Slide 7

Slide 7 text

the particulars of the con fl ict are not what we're going to discuss today If you're interested in the period, I believe there have been a few movies, tv shows, even books where you can fi nd out more

Slide 8

Slide 8 text

For our purposes today all that's important is you know that on opposing sides of the con fl ict were Germany and the United Kingdom.

Slide 9

Slide 9 text

and at the time, long distance communication was done in morse code over radio and could be intercepted by an opponent.. in much the same way we "intercept" the local top 40 station...the messages needed to be encrypted

Slide 10

Slide 10 text

the German solution for encryption was this, the Enigma machine not that much bigger than a typewriter, Enigma would encipher a given message before it was sent over the airwaves

Slide 11

Slide 11 text

The receiver of the message would also have an Enigma, given the same settings that encoded the transmission, they could reconstruct the original message

Slide 12

Slide 12 text

The British solution for *DE*crypting was this, Bletchley Park. Housed at this estate in Buckinghamshire was Britain's GC&CS: Government Code and Cipher School Their work kept secret until the 1970s, several thousand men and women, mostly women, mostly college aged, were tasked with cracking the German encyphering system.

Slide 13

Slide 13 text

If you know of Bletchley, the story you've likely heard is his Alan Turing, of the Turing Test, Turing Machines, Turing Patterns, the negative proof of the Entscheidungsproblem

Slide 14

Slide 14 text

or maybe you've seen him on the 50 pound note

Slide 15

Slide 15 text

Building on the work of Polish codebreaker Marian Rejewski and his precursor machine called "Bomba"

Slide 16

Slide 16 text

Turing realized that a quirk of the Enigma's wiring could be exploited, and designed a special-purpose computational engine that was made real by the engineering brilliance of Harold Keen and the British Tabulating Machine Company

Slide 17

Slide 17 text

after incorporating a crucial insight by English mathematician Gordon Welchman

Slide 18

Slide 18 text

Bletchley's secret weapon was christened "Bombe" on 108 cacophonous rotating drums crunched through 17,576 possible enigma settings in just 20 minutes

Slide 19

Slide 19 text

depending on who you ask, the work at Bletchley shortened the war by 2 to 4 years

Slide 20

Slide 20 text

T he Se c re tƒ L ives o f ‹ C odebr e ak e rs $ S incla i r ‹ M c Ka y If you're interested in hearing more about what it was like to be a part of Bletchley's operation.. I would recommend "The Secret Lives of Codebreakers" by Sinclair McKay

Slide 21

Slide 21 text

The enigma was operated by German communications agents working in pairs, ⭐ one to operate the keyboard, entering the message.As a key was pressed ⭐ the corresponding letter would light up on the lampboard and be written down by the second. It worked like this...

Slide 22

Slide 22 text

A A A A It's a simple electric circuit. If you're unfamiliar, think of the wire as a tube that carries electricity. When the switch is down, ⭐ the signal fl ows, when that signal touches a light, it will illuminate.

Slide 23

Slide 23 text

A A A Now imagine there are more of these simple circuits, 26 in all

Slide 24

Slide 24 text

A A A B B B C C C D D D B C D A A to A, B to B,

Slide 25

Slide 25 text

A B C D A C D B B C D If the connections between the key and and light are changed

Slide 26

Slide 26 text

B C D A C D A A B B C D Then the signal would be encoded. Press the "A" key ⭐ and "B" lights up. Knowing what letters connected, you would be able to decode it as well. That's the job of the enigma's encryption mechanism, it physically swaps the electrical connection between the key and the light.

Slide 27

Slide 27 text

A B C D E F G H I J K L M N O S A B C D E F G H I J K L M N O S W X Y Z maybe you've made a code like this before

Slide 28

Slide 28 text

A B C D E F G H I J K L M N O S A B C D E F G H I J K L M N O S W X Y Z W X Y Z when one letter is replaced by another like this it's known as a substitution cypher

Slide 29

Slide 29 text

A B C D E F G H I J K L M N O S A B C D E F G H I J K L M N O S but no matter how much the key is scrambled, substitution cyphers are trivial to break. Enigma was more

Slide 30

Slide 30 text

The heart of the enigma's encryption engine are several rotors

Slide 31

Slide 31 text

L e ft

Slide 32

Slide 32 text

L e ft R i gh t each has 26 electrical contacts on each side ⭐ and could be turned to set the machine at any of those positions.

Slide 33

Slide 33 text

internally a wire goes from a contact on ⭐ one side to a di ff erent contact on the other

Slide 34

Slide 34 text

so the signal might come in to ⭐ index 0 on the right side, and be wired to index 8 on the left, ⭐ then 2 to 21, ⭐ 3 to 14 etc

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

A A A B C D E F G H I J K L M N O S A B C D E F G H I J K L M N O S D if it remained as simple as a substitution cypher, it would be just as easy to decode

Slide 37

Slide 37 text

I

Slide 38

Slide 38 text

I I I I I I so Enigma accepted three rotors, each with di ff erent internal connections

Slide 39

Slide 39 text

I I I I I I I V V and there weren't only 3 rotors but a set of 5 to choose from

Slide 40

Slide 40 text

I I I I I I I V V and those 5 could be entered in any order for 60 possible combinations

Slide 41

Slide 41 text

I I I I I I I V V and those 5 could be entered in any order for 60 possible combinations

Slide 42

Slide 42 text

I I I I I I I V V and those 5 could be entered in any order for 60 possible combinations

Slide 43

Slide 43 text

I I I I I I I V V and those 5 could be entered in any order for 60 possible combinations

Slide 44

Slide 44 text

I I I I I I I V V and those 5 could be entered in any order for 60 possible combinations

Slide 45

Slide 45 text

I I I I V I I I V when mounted on the internal spindle, the rotors' 26 connection points lined up, and a signal could be sent through them

Slide 46

Slide 46 text

A A 0 5 4 8 coming in from the keyboard and be switched to di ff erent indexes by each rotor in turn

Slide 47

Slide 47 text

A A B E after the three rotors came a special symmetric rotor called ⭐ a re fl ector. here if 1 becomes 10, 10 becomes 1. ⭐ after passing through the re fl ector, the signal would be carried back on a di ff erent path of connections.

Slide 48

Slide 48 text

A B E A this is how enigma both encrypted and decrypted, because the path of the signal is symmetrical, typing the cipher character will return the original ⭐ but no matter how many times a letter is changed, it's weak if A always becomes E

Slide 49

Slide 49 text

B E A A J so the rotors ⭐ rotated after each character ⭐ the signal taking a new path through. the same key pressed twice in a row would yield two di ff erent encoded letters.

Slide 50

Slide 50 text

techniques that make a substitution cypher easy to break rely on repetition...are useless now. A key that changes not once a day, not once a message, but once per KEYSTROKE

Slide 51

Slide 51 text

and they didn't all rotate at the same speed. the second wheel wouldn't advance until the fi rst one made a full revolution.. and so on. (self advances)

Slide 52

Slide 52 text

that means Enigma is a polyalphabetic cypher with a new key every letter based on the starting settings.

Slide 53

Slide 53 text

2 6 each rotor has 26 positions

Slide 54

Slide 54 text

2 6 3 three rotors

Slide 55

Slide 55 text

1 7,576 makes 17 thousand 576 possible starting positions

Slide 56

Slide 56 text

1 7,576 . 6 in 60 rotor combinations

Slide 57

Slide 57 text

1 ,054,56 means 1 million 54 thousand 560 possible settings permutations

Slide 58

Slide 58 text

but the German military enigmas had another layer of encryption that commercial versions did not

Slide 59

Slide 59 text

at the front of each device was a plugboard with a connection for each letter. Up to 10 combinations could be made with short cables

Slide 60

Slide 60 text

A A E H cables that would change the signal's value between the keyboard and rotor mechanism ⭐ e ff ectively making small arbitrary changes to the cypher's key

Slide 61

Slide 61 text

In order for the German military to all be speaking the same cypher, a chart would be sent out from High command, prescribing which settings should be used on a given day. Essential coordination, because only by sharing the same starting settings would agents be able to communicate. The chart included

Slide 62

Slide 62 text

which of the fi ve rotors to use and in which order ⭐ the starting positions of the rotors ⭐ and the ten pairs of plugboard connections

Slide 63

Slide 63 text

1 , 05 4,5 5 87 0 7 3 63 1 5 2 848 954 6 5 2 6 9 9 778 68 23 2 8 84 6 8 5 4 8094 9 5 73 2 0 15 22 7 1 5 8, 9 6 2, 5 5 5 , 2 1 7 , 6 5 ! ( ! 21 0 2 ! ( ! . . 1 ! 2 6 3 . . combining all these options takes the possible settings to an astronomical ⭐ 150 million million million. portable electromechanical encryption equivalent to a 67 bit encryption key.

Slide 64

Slide 64 text

Enigma has a practical link to early computing history and because of the events of its time

Slide 65

Slide 65 text

we can directly connect Enigma and Bletchley to what we do and why we're here.

Slide 66

Slide 66 text

It's a remarkable object. that's a key word today-- object. Because Enigma will be our platform to explore principles of Object Oriented Programming, O.O.P. oop.

Slide 67

Slide 67 text

a strength of which is said to be how it "models the real world." but objects in the real world are very di ff erent than objects in a codebase

Slide 68

Slide 68 text

Enigma on the other hand.. is a physical device. it has _moving parts_. Actual objects that each perform a part of the larger whole by sending messages ..along a wire to other objects.

Slide 69

Slide 69 text

i n si d e B l e tch ley' s c o debr ea k ing op e r a t i o n If the image we're supposed to have of OOP is objects sending messages, Enigma might as well be its mascot

Slide 70

Slide 70 text

a Tu r in g - W elc hman B o m be we can recreate this mechanism in code, without abstracting our conception of an object beyond recognition

Slide 71

Slide 71 text

B l et c hl e y Par k co d e b r eake rs reu nio n 2 0 0 9 because we could literally hold in our hands the pieces of an encryption algorithm

Slide 72

Slide 72 text

T wo Truth sƒ o f So ftwa r e Dev e l o p me 1 . Requi r e me n ts wi l l ch an . 2 . We wi l l n e ve r k n ow l es t H we do r ig h t now . Let's go big right from the start with two Truths of software development ⭐ requirements will change. And this is good. If nothing needs to change, there probably aren't any users, and we'll need to fi nd another job ⭐ we will never know less than we do right now because we don't know HOW things will change

Slide 73

Slide 73 text

T wo Truth sƒ o f So ftwa r e Dev e l o p me 1 . Requi r e me n ts wi l l ch an . 2 . We wi l l n e ve r k n ow l es t H we do r ig h t now . and it's frustrating when we can't make changes, right? When a new feature request comes along and we can't deliver it to users because it would be too hard to implement?

Slide 74

Slide 74 text

T wo Truth sƒ o f So ftwa r e Dev e l o p me 1 . Requi r e me n ts wi l l ch an . 2 . We wi l l n e ve r k n ow l es t H we do r ig h t now . That's an awful feeling. We don't want to be there. but if we don't know anything.. and it's all going to change.. how CAN we build anything?

Slide 75

Slide 75 text

O b j ect O r i en t ed De s ign object oriented design is one strategy to do just that

Slide 76

Slide 76 text

m a k ing c h a ng e e asi e r 5 b y manag i n g d ep end e ncie s O b j ect O r i en t ed De s ign OO design is about making change easier by managing dependencies.

Slide 77

Slide 77 text

so what principles are we going to explore?

Slide 78

Slide 78 text

S in gle R e s po ns ibi l i i A c lass s h ou l d hav eƒ o n l y one r es p on sib i lity , 0 o n e reas o n t o c han g e Single Responsibility Principle: we'll gather together the things that change for the same reasons and separate those that change for di ff erent reasons

Slide 79

Slide 79 text

A bs tract i o n E x p ose t h e inte n t o f a n e n o t the i m pl e me nta t ion. Abstraction: we'll manage the complexity of implementation by substituting a more-easy-to-reason-about representation

Slide 80

Slide 80 text

E nc apsul a t io n P r e vent e x t e r nal c o de f r b i n v o l v e d w i t h t h e i w o r kings o f a n obj e ct. Encapsulation: Object's internal data should change on that object's own terms

Slide 81

Slide 81 text

D ep enden c y I nv ers i o H i g h-lev e l m o du les shou ld o i m p ort a n y th i ng fr o m lo w- v m o d ules. B ot h s hou l d de pe i n t erfac e s . Dependency Inversion: conventional architecture would have utility modules (low-level) consumed by higher-level ones, but we'll invert this thinking and increase reuse from top to bottom through interfaces

Slide 82

Slide 82 text

O pe n / C l o se d Pri n c S o f tware e nt i ti es s houl d f o r exte n s io n , but clos ed ¡ f o r modi f i ca t io n. Open/Closed Principle: an object should allow its behavior to be extended without modifying it's own code.

Slide 83

Slide 83 text

s ma ll si m p le o bje c t 5 s en ding m e ss ag es All of this in service of 'small simple objects sending messages'

Slide 84

Slide 84 text

Let's start up the slide-deck text editor with a new fi le, `enigma_test.rb`

Slide 85

Slide 85 text

we're going to use an abridged(?) Test Driven Development technique today, because we rubyists love tests

Slide 86

Slide 86 text

we know this because there's a test framework in the standard library!

Slide 87

Slide 87 text

A Minitest test suite is made of Ruby classes and methods, tests we write will be de fi ned inside a class that inherits from Minitest::Test we can get things moving by thinking at a high level. What does our Enigma need to do?

Slide 88

Slide 88 text

encypher a character.

Slide 89

Slide 89 text

Minitest is not a DSL, tests are methods in our class whose names start with the word test.

Slide 90

Slide 90 text

we'll initialize an instance of our Enigma class and call a cypher method asserting that it returns a string, and that string is not the one we started with.

Slide 91

Slide 91 text

Ok, that looks like a thing. So let's make that happen.

Slide 92

Slide 92 text

with a class and a method called cypher

Slide 93

Slide 93 text

Terminal.app # Running... F 1 runs, 2 assertions, 1 failures, 0 errors, 0 skips > ruby enigma_test.rb We invoke the test fi le from the command line. By requiring 'minitest/autorun' like we have, Minitest will fi nd all the runnable subclasses and tell them to do their thing. ⭐ which right now is to fail

Slide 94

Slide 94 text

Terminal.app ruby enigma_test.rb # Running... F 1 runs, 2 assertions, 1 failures, 0 errors, 0 skips > There isn't any code yet, so if that had passed, we would KNOW its a bad test.

Slide 95

Slide 95 text

Let's add another before we move on

Slide 96

Slide 96 text

time for another test

Slide 97

Slide 97 text

it should encypher into a di ff erent letter for each character

Slide 98

Slide 98 text

Terminal.app ruby enigma_test.rb # Running... FF 2 runs, 4 assertions, 2 failures, 0 errors, 0 skips > we can make sure it's not "A", and that cyphering "B" isn't the same result. Is this test going to pass? ⭐ No! of course not

Slide 99

Slide 99 text

Add an Alphabet constant, and a substitution key, with the order of real World War II enigma rotors

Slide 100

Slide 100 text

we'll make use of the rotor being an array. Get the index of the message character from the Alphabet then through that-- a letter from the rotor.

Slide 101

Slide 101 text

Terminal.app ruby enigma_test.rb # Running... .. 2 runs, 4 assertions, 0 failures, 0 errors, 0 skips > and we do it three times! Show us the tests! ⭐ Nailed it!

Slide 102

Slide 102 text

I always say, "did it work? commit!"

Slide 103

Slide 103 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Adds initial Enigma class w/ cypher method

Slide 104

Slide 104 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Made use of Test Driven Development flow, and set up initial Enigma file and functionality. Made use of Test Driven Development fl ow, and set up initial Enigma fi le and functionality.

Slide 105

Slide 105 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Made use of Test Driven Development flow, and set up initial Enigma file and functionality. The person in the front row over here really liked it. The person in the front row over here really liked it.

Slide 106

Slide 106 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch RubyConf # Changes to be committed: Adds initial Enigma class w/ cypher method Made use of Test Driven Development flow, and set up initial Enigma file and functionality. The person in the front row over here really liked it. He was nodding _a lot_. He was nodding _a lot_

Slide 107

Slide 107 text

If you need a primer on writing useful commit messages, ⭐ I hear this talk is pretty good.

Slide 108

Slide 108 text

(folding)

Slide 109

Slide 109 text

Tests are green, let's refactor. Red, Green, Refactor. But this is not a talk about TDD. ⭐ this is tho, you should watch this later

Slide 110

Slide 110 text

We've all heard of DRY, don't repeat yourself. so what stands out?

Slide 111

Slide 111 text

oh for sure but to make sure we're on the right track we should ask ourselves, "are these lines going to change for the same reason?"

Slide 112

Slide 112 text

Are they doing the same thing, do they have the same responsibility? Yes, absolutely. They're responsible for how we convert a character into it's matching integer.

Slide 113

Slide 113 text

So we gather together things that change for the same reason, to create a single source of truth

Slide 114

Slide 114 text

Terminal.app ruby enigma_test.rb # Running... .. 2 runs, 4 assertions, 0 failures, 0 errors, 0 skips > replace all the `ALPHABET.index` calls with our new method, and radio for backup ⭐ Situation green, 10-4 good buddy, over and out

Slide 115

Slide 115 text

is there another method to extract?

Slide 116

Slide 116 text

how about this? this is responsible for how we change that integer back to a letter

Slide 117

Slide 117 text

by introducing a translate method, we create the source of truth for using the rotors. If that needs to change, we can change it in one place, rather than three.

Slide 118

Slide 118 text

and look! we can use the alpha_index method

Slide 119

Slide 119 text

and remove a lot of noise.

Slide 120

Slide 120 text

now the real test.. the.. tests

Slide 121

Slide 121 text

Terminal.app ruby enigma_test.rb # Running... .. 2 runs, 4 assertions, 0 failures, 0 errors, 0 skips > still good!

Slide 122

Slide 122 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # on branch RubyConf Extracts alpha_index and translate to private methods Did it work? Commit! ⭐ Extracts alpha_index and translate to private methods.

Slide 123

Slide 123 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # on branch RubyConf Extracts alpha_index and translate to private methods We gathered the lines that would change for the same reason. We gathered the lines that would change for the same reason.

Slide 124

Slide 124 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # on branch RubyConf Extracts alpha_index and translate to private methods We gathered the lines that would change for the same reason. Guided by The Single Responsibility Principle to create a single source of truth for those behaviors. Guided by The Single Responsibility Principle to create a single source of truth for those behaviors.

Slide 125

Slide 125 text

One bene fi t from extracting methods is: we get to name things. Then what the Enigma class is really up to is easier to see.

Slide 126

Slide 126 text

We can see its translating, cyphering, that's what we expect the Enigma to do.. but it's also handling input?

Slide 127

Slide 127 text

Enigma converts letters to numbers AND uses those numbers to get a new string. Words like AND, OR, ALSO, used in describing our class can be a sign that it's doing too much.

Slide 128

Slide 128 text

let's create a new collaborator where indexing IS its purpose. If we think of the actual Enigma, maybe that's the keyboard.

Slide 129

Slide 129 text

brand new fi les, tests all set with imports and class declaration

Slide 130

Slide 130 text

test that it converts letter to alpha index. that's the behavior we're trying to move to the keyboard. Some simple assertions, do the letters change the way we would expect?

Slide 131

Slide 131 text

take advantage of the existing behavior

Slide 132

Slide 132 text

Terminal.app ruby keyboard_test.rb # Running... . 1 runs, 2 assertions, 0 failures, 0 errors, 0 skips > Simple Green! back to Enigma

Slide 133

Slide 133 text

(folding)

Slide 134

Slide 134 text

No content

Slide 135

Slide 135 text

add the keyboard

Slide 136

Slide 136 text

get rid of the alpha_index method

Slide 137

Slide 137 text

and now translate uses the keyboard instead.

Slide 138

Slide 138 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb > # Running... ... 3 runs, 6 assertions, 0 failures, 0 errors, 0 skips we're at a point where all the pieces should fi t together again, but do our tests agree? ⭐ oh! we also have more than one test fi le now, so we'll use a little ruby command line magic to run every fi le that ends in `_test.rb` ⭐ magni fi cent

Slide 139

Slide 139 text

There's something wrong with our Enigma though

Slide 140

Slide 140 text

A A A G H E Aƒ Bƒ Cƒ Dƒ E Iƒ Fƒ Gƒ Cƒ Bƒ Eƒ Dƒ Hƒ A Aƒ Bƒ Cƒ Dƒ Eƒ Fƒ Gƒ Hƒ I Fƒ Gƒ Hƒ I Hƒ Fƒ Eƒ Dƒ Gƒ Aƒ Iƒ Bƒ C Cƒ Dƒ Iƒ Hƒ Aƒ Dƒ Eƒ Bƒ F Dƒ Eƒ Aƒ Cƒ Fƒ Bƒ Gƒ Iƒ H 0 5 4 8 A I Because we're converting alpha to int and back between each rotor, we're not correctly following the connections through our device. ⭐ How do we correct? ⭐ integers the whole way through, convert only up front and at the end.

Slide 141

Slide 141 text

This will remove a lot of overhead

Slide 142

Slide 142 text

where we use the keyboard will move

Slide 143

Slide 143 text

to convert just once and stay an integer until the end. (fox) what do the tests say..

Slide 144

Slide 144 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ... 3 runs, 6 assertions, 0 failures, 0 errors, 0 skips > ooh kermit was wrong. so easy bein' green.

Slide 145

Slide 145 text

We need a lampboard too, the other side of keyboard.

Slide 146

Slide 146 text

its the keyboard but in reverse. not alphabet dot index -> get integer, it's start with an integer -> get back to the letter

Slide 147

Slide 147 text

same way, its a drop in replacement

Slide 148

Slide 148 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... .... 4 runs, 8 assertions, 0 failures, 0 errors, 0 skips > greener than Al Gore on Arbor Day

Slide 149

Slide 149 text

let's try this-- I'll say "did it work?" you say "commit!" 👆 did it work? 👉 (commit!) alright. some of you were paying attention. some of you weren't. s'okay... I'll get over it.... eventually. (( SKIP SUCCESS KID IF NO RESPONSE AT ALL ))

Slide 150

Slide 150 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts alpha/int translation to classes of their own (again) 👆 did it work? 👉 (commit!) ⭐ alright! I'm not the only person that thinks this looks like a young Patton Oswalt, am I? This commit.. extracts alpha/int translation to classes of their own

Slide 151

Slide 151 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts alpha/int translation to classes of their own (again) 👆 did it work? 👉 (commit!) ⭐ alright! This commit.. extracts alpha/int translation to classes of their own

Slide 152

Slide 152 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts alpha/int translation to classes of their own Before this, Enigma methods contained the code that implemented the behavior, preventing flexibility and reuse. Before this, Enigma methods contained the code that implemented the behavior, preventing fl exibility and reuse.

Slide 153

Slide 153 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts alpha/int translation to classes of their own Before this, Enigma methods contained the code that implemented the behavior, preventing flexibility and reuse. We extracted self-contained functionality, replacing the specific code with a message sent to new collaborators. We extracted self-contained functionality, replacing the speci fi c code with a message sent to new collaborators.

Slide 154

Slide 154 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts alpha/int translation to classes of their own Before this, Enigma methods contained the code that implemented the behavior, preventing flexibility and reuse. We extracted self-contained functionality, replacing the specific code with a message sent to new collaborators. This abstraction makes Enigma lighter, easier to understand, and opens it to new functionality. The Smaller classes offer utility and reuse to other parts of a larger system. This abstraction makes Enigma lighter, easier to understand, and opens it to new functionality. The Smaller classes o ff er utility and reuse to other parts of a larger system.

Slide 155

Slide 155 text

let's write some more tests!

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

test that it encyphers according to settings Enigma's settings would be changed by the operator, so let's add that

Slide 158

Slide 158 text

that does mean we'll need some rotors to test with

Slide 159

Slide 159 text

Let's say: starting settings means `.new`

Slide 160

Slide 160 text

We know the rotor positions, we'll assert on the precise result we expect

Slide 161

Slide 161 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... .F... 5 runs, 9 assertions, 1 failures, 0 errors, 0 skips > and a failure is the precise result we expected here, we have written no new code.

Slide 162

Slide 162 text

make some room

Slide 163

Slide 163 text

No content

Slide 164

Slide 164 text

pass in the rotors like the test says. Now we can

Slide 165

Slide 165 text

move on to changing cypher

Slide 166

Slide 166 text

(folding)

Slide 167

Slide 167 text

the rotors aren't created here anymore.

Slide 168

Slide 168 text

and the way to `translate` needs an update

Slide 169

Slide 169 text

We've begun replacing the literal references to arrays with an abstraction that allows this class to be much less involved in the implementation

Slide 170

Slide 170 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ..... 5 runs, 9 assertions, 0 failures, 0 errors, 0 skips > green like Donatello. ...ninja turtle, not sculptor.

Slide 171

Slide 171 text

lets look at translate again.

Slide 172

Slide 172 text

There's an object hiding in this class, and it's not even hiding very well. Because what is an object? It's a combination of data with behavior.

Slide 173

Slide 173 text

here's data

Slide 174

Slide 174 text

here's behavior

Slide 175

Slide 175 text

and besides, look at this method! It's a method that just calls another method by smooshing together its arguments. Keyboard and integer arrays have made this obsolete.

Slide 176

Slide 176 text

Let's not let that object stay and hide, it deserves a day in the sun, and Enigma doesn't need that extra implementation.

Slide 177

Slide 177 text

test that it translates based on its key. which in the real one is a little mess of wires between the right and left sides of the rotor

Slide 178

Slide 178 text

here the key is an array, and the argument to `.new`

Slide 179

Slide 179 text

and use a simpli fi ed key rather than the whole enigma set because this is enough to have a good test. Don't over complicate it, it's only going one step.

Slide 180

Slide 180 text

but the test is still going to error

Slide 181

Slide 181 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... .....E 6 runs, 11 assertions, 0 failures, 1 errors, 0 skips > and we expected that, this is predetermined after all... and we have the wrong number of arguments to `.new`

Slide 182

Slide 182 text

starting settings means initialize

Slide 183

Slide 183 text

and translate means brackets, we know that from before

Slide 184

Slide 184 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ...... 6 runs, 11 assertions, 0 failures, 0 errors, 0 skips > hoo-oo! emerald green

Slide 185

Slide 185 text

But Enigma is still using the old way, let's use the new rotor class instead. ⭐ Well the good news is the rotor _arrays_ are already arguments

Slide 186

Slide 186 text

but we'll instantiate and pass in the rotors instead

Slide 187

Slide 187 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... .EE.E. 6 runs, 11 assertions, 0 failures, 3 errors, 0 skips > errors errors errors

Slide 188

Slide 188 text

No content

Slide 189

Slide 189 text

instead of Enigma sending a message to itself, we have collaborators. Small Simple Objects Sending Messages, Enigma sends the message to each rotor in turn.

Slide 190

Slide 190 text

0 5 4 8 each message sent to a rotor is ⭐ one ⭐ two ⭐ three

Slide 191

Slide 191 text

(count through these) 1..⭐ 2..⭐ 3..

Slide 192

Slide 192 text

translate method? bye felicia

Slide 193

Slide 193 text

No content

Slide 194

Slide 194 text

back to the whole thing being able to fi t on the screen at once

Slide 195

Slide 195 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ...... 6 runs, 11 assertions, 0 failures, 0 errors, 0 skips > y'just love to see it

Slide 196

Slide 196 text

☝ Did it work? 👉 /commit!/

Slide 197

Slide 197 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts Rotor class This commit extracts rotor class

Slide 198

Slide 198 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts Rotor class The things that don't align to Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does The things that don't align to Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does

Slide 199

Slide 199 text

Terminal.app Extracts Rotor class The things that don't align to Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does Orchestrates and conducts the communication between these different pieces so they can stay separate from each other. # Please enter the commit message for your changes. Lines starting Orchestrates and conducts the communication between these di ff erent pieces so they can stay separate from each other.

Slide 200

Slide 200 text

Terminal.app # Please enter the commit message for your changes. Lines starting Extracts Rotor class The things that don't align to Enigma's purpose are in their own classes, and we're left with a clear picture of what the Enigma class does Orchestrates and conducts the communication between these different pieces so they can stay separate from each other. A rotor doesn't have to know what comes before or after it, and Enigma doesn't know how the work gets done. That's Dependency Inversion at work. A rotor doesn't have to know what comes before or after it, and Enigma doesn't know how the work gets done. That's Dependency Inversion at work.

Slide 201

Slide 201 text

No content

Slide 202

Slide 202 text

let's get FANCY

Slide 203

Slide 203 text

test that it encyphers a phrase correctly, no longer single character strings. ....to the command line!

Slide 204

Slide 204 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... E...... 7 runs, 12 assertions, 0 failures, 1 errors, 0 skips > sounds about right but... lets get rid of that red.

Slide 205

Slide 205 text

no change to initialize..

Slide 206

Slide 206 text

no change to initialize..

Slide 207

Slide 207 text

going to split the string into single characters and smush 'em back together.

Slide 208

Slide 208 text

it already does one character, call up our friend `.map`, do that for all the characters and that should work, right?

Slide 209

Slide 209 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ....... 7 runs, 12 assertions, 0 failures, 0 errors, 0 skips > the tests agree!

Slide 210

Slide 210 text

so lets gooo

Slide 211

Slide 211 text

We're still missing some key functionality, right? As it is, even with a phrase.. it's just a substitution cypher. Can't have that.

Slide 212

Slide 212 text

thest no repeats in consecutive cypers. if we cypher "A", then cypher "A" again, it should not be the same result twice in a row.

Slide 213

Slide 213 text

and that shouldn't only work two calls to cypher in a row, but

Slide 214

Slide 214 text

in a phrase too, show! me! red!

Slide 215

Slide 215 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ..FF..... 9 runs, 14 assertions, 2 failures, 0 errors, 0 skips > 2 failures

Slide 216

Slide 216 text

If Enigma is our coordinator, rotor position doesn't seem to fi t there... ⭐ how about the rotors themselves?

Slide 217

Slide 217 text

we want to know that the rotor can step one position, but also that it's not going to fall o ff the end of the key.

Slide 218

Slide 218 text

with the minimum amount of setup needed to test this speci fi c case

Slide 219

Slide 219 text

and here we advance advance advance. we should prefer our tests be straightforward. Coming along and reading this test later when we've forgotten what we wrote shouldn't take a lot of energy. minitest, you have anything to say?

Slide 220

Slide 220 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... .FF...FF... 11 runs, 20 assertions, 4 failures, 0 errors, 0 skips > gross

Slide 221

Slide 221 text

Position is data internal to the rotor, no accessor methods to be modi fi ed directly from outside, not even any public api revealing there is an instance variable

Slide 222

Slide 222 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... .E....FF... 11 runs, 20 assertions, 2 failures, 1 errors, 0 skips > now position is part of how we calculate what index to return ⭐ and it passes the fi rst test

Slide 223

Slide 223 text

No content

Slide 224

Slide 224 text

No content

Slide 225

Slide 225 text

this is neat. ruby has a method that moves the fi rst index in an array to the back, with an argument for how many times to rotate. also notice, does anybody else get to see this method? nope. private. ⭐ 🌈 encapsulation🌈

Slide 226

Slide 226 text

how'd we do?

Slide 227

Slide 227 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ......FF... 11 runs, 20 assertions, 2 failures, 0 errors, 0 skips > rotor is good, enigma will have to wait another moment.

Slide 228

Slide 228 text

Remember the daily settings? Position needs to be con fi gurable.

Slide 229

Slide 229 text

settings = initialize

Slide 230

Slide 230 text

Let's give it a default value, that way we don't have to update every `Rotor.new` in the codebase

Slide 231

Slide 231 text

No content

Slide 232

Slide 232 text

No content

Slide 233

Slide 233 text

and after a full rotation, it needs to let the next rotor in line tick over.

Slide 234

Slide 234 text

we'll return a boolean when advance causes position to make a full rotation.

Slide 235

Slide 235 text

By not specifying a method tied to HOW & WHEN, we leave fl exibility for future rotors to decide di ff erently, and to do it without changing a line of code outside the rotor.

Slide 236

Slide 236 text

because by the end of the war, there were rotors with two notches to tick over, or some not after a full rotation.

Slide 237

Slide 237 text

also lets not `key.rotate` a hundred times, reset position to 0 after going fully around

Slide 238

Slide 238 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ........FF... 13 runs, 22 assertions, 2 failures, 0 errors, 0 skips > the rotor tests pass, and we have what we need to make the enigma tests function so back we go

Slide 239

Slide 239 text

(folding)

Slide 240

Slide 240 text

(folding)

Slide 241

Slide 241 text

...like St Andrews we are on the GREEN! (golf reference, I apologize) ⭐ (resetting) 🙏 let's refactor.

Slide 242

Slide 242 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ............. 13 runs, 22 assertions, 0 failures, 0 errors, 0 skips > ...like St Andrews we are on the GREEN! (golf reference, I apologize) ⭐ (resetting) 🙏 let's refactor.

Slide 243

Slide 243 text

We can make it a little more comfortable in here by extracting some methods.

Slide 244

Slide 244 text

we search for things that will change for similar reasons.

Slide 245

Slide 245 text

those lines encyphered a character. why that sounds like a method name! encypher_character

Slide 246

Slide 246 text

what do these do?

Slide 247

Slide 247 text

advance rotors, done! pftt! naming things isn't hard. ( 🤔 ) naming THESE things wasn't hard.

Slide 248

Slide 248 text

(folding)

Slide 249

Slide 249 text

And we encapsulate Enigma's internal mechanisms as well by making these methods private.

Slide 250

Slide 250 text

They weren't callable from outside the class when they weren't methods, they shouldn't be now.

Slide 251

Slide 251 text

future coders will know these are not meant for re-use, and aren't tested in isolation, these messages are internal memo only.

Slide 252

Slide 252 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ............. 13 runs, 22 assertions, 0 failures, 0 errors, 0 skips > how'd we hold up? ⭐ Ver! di! gris! oh Verdigris? that's the green patina on copper..like the statue of liberty. this is getting away from me.

Slide 253

Slide 253 text

👆 did it work? 👉 /commit!/ (if they're into it: hold hand to ear, "i can't hear you"... this is fun, y'all got to try this sometime)

Slide 254

Slide 254 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior this commit implements rotor stepping behavior

Slide 255

Slide 255 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior With new behavior, Enigma is no longer a weak substitution cypher With new behavior, Enigma is no longer a weak substitution cypher

Slide 256

Slide 256 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior With new behavior, Enigma is no longer a weak substitution cypher We safeguarded the rotor's internal data, only allowing it to change via a method without exposing how the behavior is accomplished. We safeguarded the rotor's internal data, only allowing it to change via a method without exposing how the behavior is accomplished.

Slide 257

Slide 257 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. Implements rotor stepping behavior With new behavior, Enigma is no longer a weak substitution cypher By encapsulating this information, we're also protecting Rotor's collaborators from the responsibility of knowing this is what Rotors do. We safeguarded the rotor's internal data, only allowing it to change via a method without exposing how the behavior is accomplished. By encapsulating this information, we're also protecting Rotor's collaborators from the responsibility of knowing this is what Rotors do.

Slide 258

Slide 258 text

When I think about the Enigma machine, it's made up of three di ff erent high-level parts working together. The Keyboard, The Lampboard, and the encyphering mechanism.

Slide 259

Slide 259 text

The core is the rotors, but there's more to it. There's the mechanism that advances the rotors, the re fl ector, and the Spindle that the rotors sit on. We need a new small simple object to send messages to.

Slide 260

Slide 260 text

We'll call it a Spindle.

Slide 261

Slide 261 text

Instead of passing rotors to Enigma, we'll pass rotors into the spindle and the spindle to Enigma.

Slide 262

Slide 262 text

this test causes the fi rst rotor to complete a full turn, and we're asserting the second rotor got the signal

Slide 263

Slide 263 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ...EE.......... 15 runs, 24 assertions, 0 failures, 2 errors, 0 skips > yeah that was never gonna work

Slide 264

Slide 264 text

Navy Enigmas used four rotors at a time, Army and Air Force used 3, if its not hardcoded ours will have the same fl exibility.

Slide 265

Slide 265 text

Look familiar? It's the body of the `.map` from our Enigma class.

Slide 266

Slide 266 text

(folding)

Slide 267

Slide 267 text

(folding)

Slide 268

Slide 268 text

We don't know how many rotors, so we'll iterate with my favorite ennumerable method, reduce. Have you been introduced? to reduce?

Slide 269

Slide 269 text

reduce iterates the array

Slide 270

Slide 270 text

each iteration gives us the current object

Slide 271

Slide 271 text

and the return value of the previous iteration

Slide 272

Slide 272 text

but the fi rst iteration gets the argument.

Slide 273

Slide 273 text

Its the same game in `advance_rotor`, except that... except and if the step_signal is true, the rotor advances and sends its step_signal down the line.

Slide 274

Slide 274 text

We start with true so the fi rst rotor always advances.

Slide 275

Slide 275 text

and if the rotor `.advance!` returns true

Slide 276

Slide 276 text

step signal will be true for the next rotor in sequence.

Slide 277

Slide 277 text

also please don't use a ternary here unless you are also running out of room on your slides.

Slide 278

Slide 278 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ............. 14 runs, 24 assertions, 0 failures, 0 errors, 0 skips > we are so green we get mistaken for the incredible hulk

Slide 279

Slide 279 text

No content

Slide 280

Slide 280 text

Back in Enigma, the rotors are not Enigma's responsibility anymore

Slide 281

Slide 281 text

which means this is not either

Slide 282

Slide 282 text

we've got breathing room to open cypher

Slide 283

Slide 283 text

(folding)

Slide 284

Slide 284 text

(folding)

Slide 285

Slide 285 text

We are abstracting so well, we're abstracting away what class that is. No depending on any class whatsoever

Slide 286

Slide 286 text

we're only responsible for the IDEA of what that class is, the transformer.

Slide 287

Slide 287 text

if someone wants to use this class, they don't even have to use a Spindle, the modules are loosely coupled and whole new functionality doesn't NEED to change code in this fi le!

Slide 288

Slide 288 text

We know less now than we ever will... but because of OO design, it doesn't even matter. Just.. pass in a di ff erent transformer. Want to use elliptic curve cryptography? go right ahead. Want to use MD5? 1993 called and they want their algorithm back but you can! I'm excited! are you excited? [[ front row's excited! ]]

Slide 289

Slide 289 text

Terminal.app ruby -e 'ARGV.each { |f| require f }' ./*_test.rb # Running... ............. 14 runs, 24 assertions, 0 failures, 0 errors, 0 skips > green green green.. green like, i dunno all the little dots in the terminal

Slide 290

Slide 290 text

hit me baby one more time 👆 did it work? 👉 /commit!/

Slide 291

Slide 291 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility This commit abstracts encyphering away from Enigma's responsibility.

Slide 292

Slide 292 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Enigma is Open for Extension and Closed for Modi fi cation, enabling painless re-use in ways we don't have to try and predict.

Slide 293

Slide 293 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... Lead by OO Design principles we built a replica Enigma that is easy and fun to work with.

Slide 294

Slide 294 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like using tech and ideas that stand on the shoulders of giants like

Slide 295

Slide 295 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing Alan Turing

Slide 296

Slide 296 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing, John von Neumann John von Neumann

Slide 297

Slide 297 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing, John von Neumann, Grace Hopper Grace Hopper

Slide 298

Slide 298 text

Terminal.app # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Abstracts encyphering away from Enigma's responsibility Enigma is Open for Extension and Closed for Modification enabling painless re-use in ways we don't have to try and predict. Lead by OO Design principles we built a replica Enigma that is easy and fun to work with... ...using tech and ideas that stand of the shoulders of giants like Alan Turing, John von Neumann, Grace Hopper and Yukihiro Matsumoto. and Yukihiro Matsumoto ⭐ what a ride!

Slide 299

Slide 299 text

<< breath >>

Slide 300

Slide 300 text

S ingl e Re s ponsi b i l i ty Single Responsibility: Objects and methods that strive for a cohesive uni fi ed purpose.

Slide 301

Slide 301 text

S ingl e Re s ponsi b i l i ty A bstr acti o n Abstraction: Relocating implementation, replacing with a simpler-to-reason-about representation

Slide 302

Slide 302 text

S ingl e Re s ponsi b i l i ty A bstr acti o n E ncap sula t ion Encapsulation: An object should respond, react and update on its own terms.

Slide 303

Slide 303 text

S ingl e Re s ponsi b i l i ty A bstr acti o n E ncap sula t ion D epen denc y Inve r s i o n Dependency Inversion: Higher level objects operate without being involved in the speci fi cs of those they send messages to.

Slide 304

Slide 304 text

S ingl e Re s ponsi b i l i ty A bstr acti o n E ncap sula t ion O pen/ Clos e d D epen denc y Inve r s i o n Open for extension and closed for modi fi cation...because we don't even need to!

Slide 305

Slide 305 text

S ingl e Re s ponsi b i l i ty A bstr acti o n E ncap sula t ion O pen/ Clos e d D epen denc y Inve r s i o n all in service of

Slide 306

Slide 306 text

S m a l l S i m p l e O b j e c t s S e n d i n M e s s a g e s small simple objects sending messages

Slide 307

Slide 307 text

No content

Slide 308

Slide 308 text

C hang e is hard. because change is hard

Slide 309

Slide 309 text

C hang e is hard. B ut i t do e sn't h a v e t but it doesn't have to be

Slide 310

Slide 310 text

Thank you all so much, this was fun lets do it again sometime.

Slide 311

Slide 311 text

R e ad i ng t h e R uby ¡ o n R a il s d ocu ment a t i o n H . . .b u t l i k e f or f u n s i es F o un d w h e r eve r yo u g e t y ou r p odc asts , b u t h ey t r y O verc a s t - > c o de im a g e s m ade w i t h c o m e s a y h i a t t h e t h o u g h t b o t b o o t h If you want to chat about more features to implement with Enigma, we didn't even get to the re fl ector or the plugboard, or a lampboard that returns html instead of a string, or a keyboard that's an api endpoint, or maybe you too have feelings about how Turing was murdered by his own government? or want to chat about Bletchley Park.. or like.. Object Orientation.. I'm going to be hanging around the thoughtbot booth a lot tomorrow, come say hi.