Tuesday, February 17, 2015

Share Your Local Web Server Publicly using ngrok

As a web developer, my workflow often includes writing a little code, firing up a local web server, and doing a quick smoke test to make sure things look alright. Occasionally, I'll encounter a situation where I'll need someone else (coworker, client, etc.) to provide some feedback on a design decision before moving forward. If I'm in the office, it's easy. I'll just call them over to take a look.

However, there are times when I need to share my local changes with someone remotely and get feedback quickly. If the change is relatively minor, deploying to some staging environment might be overkill. How can I expose my local web server publicly so my clients can view my changes and provide immediate feedback?

Enter, ngrok!


ngrok, creates a secure tunnel from a randomly-assigned, public internet address to a locally running web service. It also captures any traffic moving through the tunnel, allowing users to inspect HTTP request data. ngrok has several uses, and publicly exposing a local web server is one of them.

Installation


There really is no "installation" required. You simply visit the download page and follow the instructions. Since I'm an Ubuntu user, I downloaded the Linux .zip file, unzipped the binary, and began using it. Easy as pie!

Running a Web Server

Let's expose a local Rails web server! We'll assume a Rails project already exists and is ready to start. So, lets fire it up:
$ rails server

=> Booting WEBrick
=> Rails 4.0.4 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
Now, if we go to http://localhost:3000, we should see something resembling the following:


Sharing Our Local Web Server

To expose our local web server to anyone over the internet, we simply navigate to our ngrok binary and run the following:
$ ./ngrok 3000
The "3000" argument is the local port of our web server. If you are hosting something other than Rails, it may launch on a different port. In this case, simply replace "3000" with the port number of your web server.

Once ngrok is launched, it will display the following:
ngrok (Ctrl+C to quit)

Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    http://2779ffc7.ngrok.com -> 127.0.0.1:3000
Forwarding                    https://2779ffc7.ngrok.com -> 127.0.0.1:3000
Web Interface                 127.0.0.1:4040
# Conn                        0
Avg Conn Time                 0.00ms
Using the information provided above, we have our public web address: http://2779ffc7.ngrok.com. We can share this URL with our collaborators! Any visits to this URL will be tunneled to our local web server. As people visit the URL, ngrok will update by displaying any HTTP requests flowing through the tunnel:
HTTP Requests
-------------

GET /favicon.ico              200 OK
GET /                         200 OK

Further Request Inspection with the Dashboard

ngrok provides a introspection dashboard which is hosted locally at http://localhost:4040/.


Since all HTTP traffic is captured by ngrok, more detailed information about each request can be explored on the dashboard. The dashboard updates in real-time. So, as people view your exposed website, the dashboard will update along with each request. You can explore request time, duration, headers, parameters, etc. It even pretty-prints JSON and XML responses to make them easier to read.

Conclusion

As more companies allow remote-working among their employees, collaborative tools utilizing the web will become more important. In the fast-paced world of web development, gathering feedback quickly is much easier because of tools like ngrok!

Go on, give it a try! Let me know your thoughts by leaving a comment.

Friday, February 13, 2015

Replacing the Screen on the Lenovo Thinkpad X220

Back in 2011, I purchased a Thinkpad X220 to replace my aging Thinkpad T61. It's a great laptop, serving me well for just about four years now! Unfortunately, my screen recently began exhibiting the "vertical line" issue, which is basically a vertical strip of discoloration along a part of the screen. You can read more about this common issue on Thinkpad Forums, Notebook Review, or this Youtube video.

After four years without any major problems, my X220 was finally showing its age. However, it's really easy to replace the LCD panel on the X220 (or any Thinkpad for that matter)!

Tools required:
  • a small Philips screwdriver
  • a flat-head screwdriver(for prying)

Finding the Correct Replacement LCD

Lenovo provides a system service parts list document for most of their products. Each document contains a diagram of all the components and information about each part. This is part of the diagram from the X220 System Parts List:



Navigating through the diagram, I found the LED Premuim LCD Service Parts List. (Note: This is for X220s with the IPS screen option.) By clicking the LCD panel on the diagram, I was redirected to the following table:

LCD panel, 12.5-in. HD LED backlight
Product ID FRU CRU
4286-CTO, 23x, 24x, 25x, 36x, 37x, 3Ux, 3Yx, 42x, 4Nx, 4Qx
4287-CTO, 2Ax, 2Dx, 2Ex, 2Fx, 2Lx, 2Mx, 2Sx, 2Tx, 3Hx, 3Kx, 3Px, 3Qx, 4Rx, 4Vx, 4Wx,59x, 5Ax, 5Xx, 5Yx, 6Cx, 6Fx, 6Gx
4289-CTO
4290-CTO, 2Hx, 2Jx, 2Mx, 2Nx, 2Qx, 2Wx, 33x, 34x, 35x, 3Xx, 3Zx, 42x, 47x, 48x, 4Fx,4Lx, 4Sx, 4Tx, 4Ux, 4Xx, 4Yx, 4Zx, 52x, 53x, 57x, 58x, 5Gx
4291-CTO, 2Ex, 2Ux, 2Vx, 2Wx, 2Zx, 42x, 47x, 48x, 49x, 4Ax, 4Bx, 4Cx, 4Xx
93P5675 N

Let's break down and define each section:

Product ID: The Product ID can be found on a sticker underneath the laptop, over to the left. Depending on the configuration of the laptop, this ID will vary.
Field Replaceable Unit (FRU) ID: An FRU ID is a 7-digit number used to identity specific components in a system. Service technicians can use this number to easily find and ensure a direct replacement for a defective part.
Customer Replaceable Unit (CRU) ID: A CRU ID is a single-digit number used to specify the difficulty level of replacing a component in a system for a customer. The following describes what each value means:

1 = easy to replace with little or no tools
2 = more difficult to replace
N = customer should not replace

My Product ID happens to be 4286-CTO. However, the table tells us it doesn't matter what the Product ID is. The FRU is the same for all of them! Using the FRU, 93P5675, it should be relatively easy to find a suitable replacement for my broken LCD panel!

Shopping for a Good LCD

There are several places online you can find decent replacement laptop components. I've only had experiences buying LCDs from two stores: Screen Country and East Coast LCDs. Both are really easy to use and have decent pricing. A quick search for the FRU on East Coast LCDs led me to the exact LCD panel I needed!



There are many other online vendors that sell replacement parts (eBay, Amazon, AliExpress). A simple Google search of the FRU yields some pretty good results!

As of now, the average price for an X220 replacement LCD is about $45-$70, shipped.

LCD Panel Removal and Replacement

Lenovo provides instructions on how to remove and replace the LCD in the X220 Hardware Maintenance Manual. I found this Youtube video extremely helpful.

The following is my step-by-step process.

Remove the battery.




Using a flat-head screwdriver (or knife), gently pry off the screw covers on the front bezel of the LCD housing.





Using a Philips screwdriver, remove the screws holding the bezel in place.




With the aid of a flat-head screwdriver, gently pop the bezel off along the edges. The bottom is tricky. Be patient!






There are four screws holding the LCD panel to the housing. Remove these with a Philips screwdriver.







There are three more screws attaching the LCD panel to the hinges. Remove these with a Philips screwdriver.






Using a flat-head, gently lift the LCD panel up and off the housing, but not all the way off! It is still attached to the motherboard by the LCD cable.




Flip the LCD panel over to the backside and locate the LCD cable near the bottom.




There is a piece of tape securing the LCD cable to the panel. Gently remove the tape and slide the LCD cable down and out.




Voila! The LCD panel can now be fully removed from the LCD housing.



This is the new panel, packaged very securely by East Coast LCDs!




Now, just do the reverse! Reattach the LCD cable to the new LCD panel.





Before screwing everything back in, make sure things work. Looking good so far!




After screwing everything back in, remove the protective plastic left on the new LCD panel.



Good as new!



Conclusion

Thinkpads are really easy to modify and repair. In addition to replacing my broken screen, I ripped out the keyboard for cleaning and installed a new 128 GB solid-state drive. I have even more plans to upgrade the memory to 8 GB from 4 GB. My X220 has never been better and will, hopefully, continue to last a very long time!

Have any comments, questions, critiques? Let me know below. Happy tweaking!

Thursday, February 12, 2015

SOLID Review: Open/Closed Principle


Note: This is part of a series of articles reviewing the five SOLID Principles of object-oriented programming.

The Open/Closed Principle was first coined by Bertrand Meyer in his book Object Oriented Software Construction. Meyer states that the implementation of any class in a system should be changed only to correct errors. Any new features are introduced by creating additional classes that extend or modify the existing code.

Meyer's idea is more popularly described as follows:

"Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification."

Following this principle brings a major benefit. We are less likely to break the existing system's functionality if we minimize any changes to the original implementation. This increases stability, extensibility, and maintainability.

Open for Extension, Closed for Modification

Classes abiding by the Open/Closed Principle exhibit two important characteristics: they are open for extension and closed for modification.

A class is closed for modification when its internal implementation is hidden away. Its only interactions with the outside world are through a set of public methods known as its interface. All its internal logic is assumed to be correct. Therefore, it shouldn't need to change.

A class is open for extension if its behavior can be enhanced or modified by adding new code on top of the existing implementation. Classes must be designed in a way that lets consumers "plug in" or "inject" new logic.

Abstracting Behaviors

The main key in adhering to the Open/Closed Principle is proper abstraction of key behaviors. These behaviors are abstracted and encapsulated nicely behind a shared interface. By keeping classes dependent on these abstractions, new behaviors can easily be introduced without changing the existing code.

A Simple String Transformer

Suppose we need a simple application that transforms strings. Somewhere in our code, we have a service object called Transformer which takes a string and transforms it into a some other object:
require 'json'

class Transformer
  def initialize(string)
    @string = string
  end

  def transformed_string
    JSON.parse(@string)
  end
end

Transformer.new('{"foo": "bar"}').transformed_string
# { "foo" => "bar" }

Simple enough! We can transform strings into Ruby hashes. Now, a new feature requires us to transform strings into binary in addition to Ruby hashes. Let's add the new functionality to our Transformer class:
require 'json'

class Transformer
  def initialize(string, type)
    @string = string
    @type = type
  end

  def transformed_string
    if @type == :json
      JSON.parse(@string)
    elsif @type == :binary
      @string.unpack('B*').first
    end
  end
end

Transformer.new('Hello', :binary).transformed_string
# "0100100001100101011011000110110001101111"
Great! Now we can pass in strings and specify the type of transformation to use. So far, so good. However, yet another new feature requires us to add support for yet another transformation: converting to MD5.

require 'json'
require 'digest'

class Transformer
  def initialize(string, type)
    @string = string
    @type = type
  end

  def transformed_string
    if @type == :json
      JSON.parse(@string)
    elsif @type == :binary
      @string.unpack('B*').first
    elsif @type == :md5
      Digest::MD5.hexdigest @string
    end
  end
end

Transformer.new('Hello', :md5).transformed_string
# "8b1a9953c4611296a827abf8c47804d7"
As you can see, our transformed_string method is starting to get quite ugly. It is also brittle, as we keep modifying the logic inside to accommodate new features! How can we make this class more open to extension?

Find and Extract the Abstraction

To make Transformer more open to extension, we need to make it depend on an abstract behavior rather than handling many different transformations. It seems like we keep on adding new types of transformations to our class, so let's abstract this behavior out!

Solution: Inheritance

We'll start by turning our Transformer into an abstract base class.
class Transformer
  def initialize(string, type)
    @string = string
    @type = type
  end

  def transformed_string
    raise 'Implement me!'
  end
end
The class looks the same. However, the application will now depend on Transform's sub-classes to implement the transformed_string behavior. Taking this approach, we can now create new types of transformations by adding new classes:
class MD5Transformer < Transformer
  def transformed_string
    Digest::MD5.hexdigest @string
  end
end

MD5Transformer.new('Hello').transformed_string
# "8b1a9953c4611296a827abf8c47804d7"
However, we've almost completely rewrote our existing implementation to make way for this solution. What about other classes in our application that depended on instances of Transformer? We would have to change class-names and signatures all over our application to accommodate our refactor.

Better Solution: Dependency Injection

Again, we want to extract and encapsulate the transformation behavior out and make Transform depend on an abstraction. We can achieve this by creating different Transformations and injecting them into Transform through its constructor:
class Transformer
  def initialize(string, transformation)
    @string = string
    @transformation = transformation
  end

  def transformed_string
    @transformation.transform(string)
  end
end

class BinaryTransformation
  def self.transform(string)
    string.unpack('B*').first
  end
end

Transformer.new('Hello', BinaryTransformation).transformed_string
# "0100100001100101011011000110110001101111"
This is a bit better, as the signature of our constructor hardly changes, but the implementation of Transform now depends on an abstraction known as Transformation. Any new (or existing) transformation behaviors can be added by creating new classes and injecting them into Transform!
require 'json'
require 'digest'

class JSONTransformation
  def self.transform(string)
    JSON.parse(string)
  end
end

Transformer.new('{"foo": "bar"}', JSONTransformation).transformed_string
# { "foo" => "bar" }

class MD5Transformation
  def self.transform(string)
    Digest::MD5.hexdigest string
  end
end

Transformer.new('Hello', MD5Transformation).transformed_string
# "8b1a9953c4611296a827abf8c47804d7"

Conclusion

This is a very simple example of how to design classes that are open for extension and closed for modification. It's important to remember to balance this principle against real-life requirements. If applied too soon, the Open/Closed Principle might lead to unnecessary abstractions, making code difficult to understand. Always take the simplest approach first. Then, if necessary, refactor code with the Open/Closed principle in mind.

Happy coding!