It is easy to take for granted Komodo IDE's superb debugging support. Komodo excels at debugging common scripting languages like Perl, Python, Tcl, and Ruby. It can also debug PHP, Node.js, and XSLT. With Komodo X, the debugger supports an all new target: Google Chrome. What is the secret to Komodo's debugging prowess, and how does Komodo communicate with such an unorthodox target as Chrome? Read on to find out!
Under the Hood
Under the hood, Komodo's debugger makes use of a debugging protocol called DBGP, which was co-designed by our developers here at ActiveState. This protocol is based on bi-directional socket communications between a debug server (typically Komodo or another IDE with DBGP support) and a debug client (typically the code being debugged).
A typical debug session begins when Komodo kicks off the debug client in a separate process that initializes the script to debug. Komodo then sits and waits for a connection. The client initiates the connection, sends an initialization packet, and waits for instructions from the server. At this point Komodo can issue DBGP commands to set breakpoints, run/pause/step, inspect variables, and so on.
What exactly is the debug client? More often than not it is just a script (or set of scripts) written in the language to debug that performs the debugging, and then communicates with the debug server. For example, the Python debug client is a Python module composed of a number of Python scripts. This module makes use of Python's built-in debugging facilities in order to actually perform the debugging, and it uses the socket routines provided by Python's standard library in order to communicate with the debug server.
Chrome and Komodo
Here is where we stand:
- Komodo's debugging facilities send and receive messages via the DBGP Protocol.
- Chrome's debugging facilities send and receive messages via the Chrome Remote Debugging Protocol (henceforth referred to as "CRDP").
- These protocols are completely different.
- What to do?
In our minds, the most reasonable thing to do was create an "interpreter", but not in the sense of an interpreter for a programming language. No, this interpreter would act sort of like a foreign language translator. It understands both protocols and can act as the "middle man" in-between Komodo and Chrome. Any DBGP messages sent by Komodo would be interpreted and translated into CRDP messages before being forwarded on to Chrome. Any CRDP messages received by Chrome would be interpreted and translated into DBGP messages before being forwarded to Komodo.
We decided that this interpreter should be a stand-alone program spawned by Komodo. Why not build it into Komodo and run it in-process? Well by nature the web is asynchronous. If the interpreter was built into Komodo's main process, any time Komodo sent a debug command, its interface would "block" (or wait) until a response was received. We know in the web world this is simply bad practice. Okay, then why not create a custom web-page in Chrome and have it do the debugging and communication work behind the scenes? Chrome's tabs are separate processes, no? That is a good point, but a very important aspect of developing this interpreter is the ability to easily unit test it. At the time, there was/is no viable way to do this from Chrome itself.
When it comes to executing those unit tests, prior to each unit test body being run, there is a "setUp" function that instantiates the "ThreadedTestClient" (which starts Chrome and the interpreter). When the main unit test body is executed, it makes the connection with the interpreter and then proceeds with its particular suite of tests. Afterwards, a "tearDown" function kills the "ThreadedTestClient" and Chrome. All of this happens automatically for each unit test when we execute our
python test.py command. This is far more convenient than manually starting Chrome and working through a scripted set of instructions that re-tests all of our debugging functionality after making a small change.
The absolute coolest part about Komodo's use of the DBGP protocol for its debugging functionality is that once you understand the protocol, you can develop your own debug client completely independently of Komodo and then, when you are ready to integrate it with Komodo, it will slip on like a glove and just work. That is exactly how we developed this Chrome debug client, and how we developed the all new Ruby 2.1+ debug client, which was also introduced in Komodo X. In an upcoming blog post, we will illustrate this process at a deeper level with a completely new programming language. Stay tuned!