14

I love that writing Python, Ruby or Javascript requires so little boilerplate. I love simple functional constructs. I love the clean and simple syntax.

However, there are three things I'm really bad at when developing a large software in a dynamic language:

  • Navigating the code
  • Identifying the interfaces of the objects I'm using
  • Refactoring efficiently

I have been trying simple editors (i.e. Vim) as well as IDE (Eclipse + PyDev) but in both cases I feel like I have to commit a lot more to memory and/or to constantly "grep" and read through the code to identify the interfaces. This is especially true when working with a large codebase with multiple dependencies.

As for refactoring, for example changing method names, it becomes hugely dependent on the quality of my unit tests. And if I try to isolate my unit tests by "cutting them off" the rest of the application, then there is no guarantee that my stub's interface stays up to date with the object I'm stubbing.

I'm sure there are workarounds for these problems. How do you work efficiently in Python, Ruby or Javascript?

3 Answers3

2

A quick search turned up Rfactor for Ruby (interview here) and bicycle repair man for Python. Not sure how good either are...but they're worth looking at.

Michael Brown
  • 21,684
  • 3
  • 46
  • 83
2

Navigating the code

Get a better editor than VIM.

I use Komodo Edit.

I feel like I have to commit a lot more to memory

Good. Thinking is good. I find that "learning" leads eventually to "memory".

Constantly "grep" and read through the code to identify the interfaces.

This is typical. If you can't remember them, then they're too complex, aren't they? Time to simplify.

Simple is hard to create. But when you have trouble remembering, it's a symptom of bad design.

I use grep. It works for me. My Komodo Edit has lots of nice search. So does Notepad++

Identifying the interfaces of the objects I'm using

Doc Strings and the help() function work. I use them. Daily.

Refactoring efficiently... it becomes hugely dependent on the quality of my unit tests.

That's not news. That's always been true, even in a static language.

In a static language, we often get lazy, assuming that -- as long is it compiles -- it's really likely to work. This is manifestly false, but we get lazy.


I'm sure there are workarounds for these problems.

These aren't "problems" and don't require "workarounds".


A dynamic language is precisely about not knowing the type of the objects you manipulate. When you receive a parameter, you assume it defines a "quack()" and a "feathers()" method, but you don't know where there documentation is (in fact, they will have multiple docstrings in their multiple implementations).

"not knowing the type of the objects"? Really. When I design the client of an object, I know what type I designed.

When I define a service, used by multiple clients, the "exact" type is not relevant, when I have a defined the required interface of quack() and feathers().

Finally, I have the Read-Execute-Print-Loop and other tools to determine the "exact" type in the rare cases when I have a subtle problem. That's what I actually use every day.

>>> x = some_mystery_factory( some, args )
>>> type(x)
>>> dir(x)

Doesn't seem too difficult -- at least in Python -- to unwind the type of an object. Must dynamic languages have a REPL, making it pretty easy to see what's going on.

You don't know the expected parameter order either. It seems hard for an IDE to help there.

That doesn't make much sense. help() works.

And my IDE can often locate the definition. Not always -- some convoluted dynamic constructs can easily conceal the base class. In that case, I have to actually think about the object's class to locate the method definition. Of course, I'm writing the code, so there's little (or no) mystery there.

S.Lott
  • 45,264
  • 6
  • 90
  • 154
  • 7
    I feel like I could argue that being forced to commit more to memory gives you *less* capacity for thinking... – Nicole Feb 02 '11 at 21:32
  • @Renesis: Memorization isn't evil if there's any kind of pattern or system to the interfaces. – S.Lott Feb 02 '11 at 21:33
  • 1
    I agree with @Renesis memorizing interfaces takes my mind away from the real thinking. I couldn't care less how another coder on my team decided to order the parameters. The fact that a large codebase uses a lot of different libraries with different naming standards is not infrequent, and it is often impossible or impractical to simplify or unify these components. – Philippe Beaudoin Feb 02 '11 at 23:46
  • Re: Doc strings, they're fine when you know the type of the object, but often you don't and you have to look that up. – Philippe Beaudoin Feb 02 '11 at 23:53
  • @Philippe Beaudoin: "a large codebase uses a lot of different libraries with different naming standards". Please **update** your question to include all the facts. "know the type of the object"? How can you not? – S.Lott Feb 03 '11 at 00:17
  • A dynamic language is precisely about not knowing the type of the objects you manipulate. When you receive a parameter, you assume it defines a "quack()" and a "feathers()" method, but you don't know where there documentation is (in fact, they will have multiple docstrings in their multiple implementations). You don't know the expected parameter order either. It seems hard for an IDE to help there. (Also: I have updated my question.) – Philippe Beaudoin Feb 03 '11 at 16:53
  • @Philippe Beaudoin: "not knowing the type of the objects"? Really. When I design things, I know what type I designed. Further, the "exact" type is not relevant, when I have a defined interface of `quack()` and `feathers()`. Finally, I have the Read-Execute-Print-Loop and other tools to determine the "exact" type in the rare cases when I have a subtle problem. That's what I actually use every day. – S.Lott Feb 03 '11 at 17:01
  • Could you update your answer to talk about the "Read-Execute-Print-Loop" seems like a potentially useful tool. – Philippe Beaudoin Feb 03 '11 at 17:32
  • 1
    grr... there is no better editor than Vim :P – Anto Feb 03 '11 at 18:38
  • I beg to differ. Some refactorings that are bulletproof in static languages are tricky in dynamic languages (like Python). Renaming a local var has few degenerate cases, but _robust_ class member renaming is hardly doable at all. Also, you need tests for silly cases like a name wrongly typed or not even defined in a particular path of execution. REPL is nice for fiddling with initial design; when you have to troubleshoot issues on a big deployed system, it helps little. The bigger the system is, the less advantages of a dynamic language you feel. Dynamic parts should be kept smallish. – 9000 Mar 10 '11 at 13:12
  • @9000: "class member renaming is hardly doable at all." I suppose. I've done it enough times that I fail to see how it's "hardly doable". Unit tests seem to reveal problems pretty quickly. Maybe my 65,000 lines of code is too small a system to have serious problems. – S.Lott Mar 10 '11 at 13:25
  • @s-lott: Probably you rarely see code that uses much of `getattr` and monkey patching. Objects of which class get passed to a particular function is often not apparent, too: should you rename that `foo.feathers()` to `foo.getFeathers()` because `Duck` is the only expected type of input, or let it stay because it's a part of a bigger interface and you'll break things? Python usually provides no hints, even if you build proper call graphs. Being a developer of PyCharm, I keep facing such issues with real Python code, and handling them gracefully is not always straightforwardly easy. – 9000 Mar 10 '11 at 13:54
1

There is a company - JetBrains - authors of the ReSharper, TeamCity and IDEA. They recently started to look at dynamic languages and already released their tools for Python, PHP and Ruby.

The quality is great. These are not another plugins for your favorite IDE but fully featured IDEs and they are quite good for refactoring/navigation/debugging etc - they are like IDEA lite.

Andrey Taptunov
  • 679
  • 3
  • 7