diff --git a/content/about.md b/content/about.md index f3ae4fc..7063b6d 100644 --- a/content/about.md +++ b/content/about.md @@ -6,11 +6,11 @@ draft: false # Summary -Software engineer that loves to solve hard problems in interesting ways. Currently, I do full-stack Ruby on Rails with React.js, and I work on a networked Python application. I'm working at [Verodin, Inc.](https://verodin.com) helping companies measure the effectiveness of their cybersecurity in a continuous manner. +Software engineer working currently for Kickback Rewards Systems doing all manner of things. Currently into ETL, embedded C and full-stack Python with React and Django. Worked full-time as a software engineer for the past 5 years, doing full-stack Python work in Django, Ruby on Rails, React, Jenkins, Docker builds, embedded C, Machine Learning, System Administration, CI/CD pipelines, TDD and more. When not working I'm with Rebecca, my better half, or out trying to be active in some way. Moved to TN after living in VA my whole life and excited for where life will take me. # Interests -Tech-wise, there will always be more to know, and more to do. Currently I am interested in statistics and machine learning, and how to apply these fields to common problems I encounter. I also am a programming language fanatic. My favorite programming languages include but are not limited to: Julia, Python, C, Scheme, Racket, Ruby, Javascript, and R. +Embedded C, Go, Entrepreneurship, Volunteering, Sports # [Resume](https://jake-windle.gitlab.io/cv.pdf) diff --git a/content/post/probability-in-testing.md b/content/post/probability-in-testing.md new file mode 100644 index 0000000..b72f619 --- /dev/null +++ b/content/post/probability-in-testing.md @@ -0,0 +1,72 @@ +--- +title: "Adding probability to testing: Golang" +date: 2019-05-23T17:17:17-04:00 +draft: false +tags: ["go", "testing"] +--- + +In my work as a Software Engineer at Kickback Rewards Systems, I recently wrote an application that essentially reads packets from a TCP stream. +It's amazing to me that writing a concurrent application that reads bytes from a TCP stream is SO EASY with Go, in less than 150 LOC! +We've had similar applications in C and Python that are much larger than that at my company! +Anyway, this application merely needed to mock the functionality of the production system, so that we could test the transmission of a new packet +type from our client code. The client expected some entity acting as the server in a socket connection that would first read bytes from the stream +to determine the length of the payload, then the payload itself. The server has to respond to the client in a similar manner, length preamble, and +payload of response. + +An interesting requirement arose amid development of this mock server. The requirement was that the server should simulate an actual internet connection, + sometimes terminating the client's connection +too early, sometimes delaying a response to the client, and sometimes just not responding at all. The trick to this though is that this wacky behavior +needed to be inconsistent, something that happened seemingly randomly. To accomplish this, I developed a neat pattern using closures and function +pointers. + +Enter our goroutine, which is obviously not my real production code: + +```go +// Main and rest of program not included, it's not important to this example. + +// Our goroutine.. called in the main socket listening loop +func handleConn(conn net.Conn) { + // Do some work and respond. +} +``` + +This is a pretty standard pattern, develop a function intended to be used as a goroutine, and call it in some loop passing a connection from a successful +`net.Listener.Accept()` call. What I did to add a little chaos to this function, was utilize a little bit of closure trickery >:). To introduce any +amount of chaos to your application, a function like this will do: + +```go +// Flip a coin, and do the action on tails... +func chaos(action func()) { + if rand.Intn(10) > 5 { + // Executing our function pointer. + action() + } +} +``` + +On its own, this function may seem harmless. One may ask why you would want to flip a coin then do something if we achieve a certain result. The answer +to that is simple, and that's where closures come in. Let's modify my goroutine from before to do something nasty. + +```go +func handleConn(conn net.Conn) { + // Now let's introduce some... chaos + chaos(func() { + fmt.Println("Oh no, something bad happened!") + conn.Close() + + // don't worry about this. + runtime.Goexit() + }) + + fmt.Println("Phew, nothing's gonna happen, let's continue.") + // Do the work. +} +``` + +The way this works is simple, we pass an anonymous function as the argument to chaos, noted above as type `func()`. This anonymous function that we +create has access to any variables defined in its enclosing scope. `conn`, a function parameter, is defined in the same scope as the anonymous function, +thus it is perfectly valid to reference it from within the function. Now, when the function is executed in `chaos` like this: `action()`, it is still +holding a valid reference to the conn object, resulting in `conn.Close()` being called terminating the client's connection with the server. Use this +pattern any time you would like to introduce a little bit of chaos to your testing. + +