
Reworder – A tale of learning Python and launching an app in five days. - sahillavingia
http://sahillavingia.com/blog/2010/10/26/reworder-a-tale-of-learning-python-and-launching-an-app-in-five-days/
======
Luyt
_make sure you use tabs to format all of your Python code_

I disagree. Idiomatic Python uses 4 spaces per indent.

 _Either solely use tabs or solely use spaces, they don’t work well together,
at least in my experience_

Mixing tabs and spaces is indeed very unwise. You can run Python with the -tt
option to make sure you're consistent.

 _Read Style Guide for Python Code for more advice on this front_

I agree ;-) The author probably refers to PEP8,
<http://www.python.org/dev/peps/pep-0008/>

~~~
bwooceli
Could not agree more!!!! If you're a vimmy, be sure to add this friendly
helper into your .vimrc

:set tabstop=4

:set shiftwidth=4

:set expandtab

~~~
mattdawson
Or, if you only want to use these settings for python files, create a
~/.vim/ftplugin/python.vim file. Mine looks like this:

    
    
      setlocal tabstop=4
      setlocal softtabstop=4
      setlocal shiftwidth=4
      setlocal textwidth=80
      setlocal smarttab
      setlocal expandtab
      setlocal smartindent

~~~
whimsy
Today I learned...

Thanks.

It looks like ftplugin is a native vim extension - is that correct?

~~~
mattdawson
I'm a bit late in responding, but yes, it's a native vim extension. To make
sure your plugins are loaded automatically, put

    
    
      filetype plugin on
    

in your .vimrc.

------
gurraman

      Traceback (most recent call last):
        File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 513, in __call__
          handler.post(*groups)
        File "/base/data/home/apps/reworder/1.345779356045891791/reworder.py", line 122, in post
          headers={'Content-Type': 'application/x-www-form-urlencoded'}).content)
        File "/base/python_runtime/python_lib/versions/third_party/django-0.96/django/utils/simplejson/__init__.py", line 232, in loads
          return cls(encoding=encoding, **kw).decode(s)
        File "/base/python_runtime/python_lib/versions/third_party/django-0.96/django/utils/simplejson/decoder.py", line 251, in decode
        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
        File "/base/python_runtime/python_lib/versions/third_party/django-0.96/django/utils/simplejson/decoder.py", line 270, in raw_decode
          raise ValueError("No JSON object could be decoded")
      ValueError: No JSON object could be decoded
    

Entered text "this is a test." and hit submit.

~~~
sahillavingia
Figured out the bug: hit the API request limit. Argh!

------
colbyolson

        Traceback (most recent call last):
          File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 513, in __call__
            handler.post(*groups)
          File "/base/data/home/apps/reworder/1.345779356045891791/reworder.py", line 140, in post
            synonym = synonym_for_word(stripped_word, tag)
          File "/base/data/home/apps/reworder/1.345779356045891791/reworder.py", line 201, in synonym_for_word
            return result.get(word_type)['syn'][0]
        KeyError: 'syn'

~~~
olalonde
Hence, Teach Yourself Programming in Ten Years[1]. All kidding aside, I'm
pretty sure it's unrelated to the actual code :)

[1] <http://norvig.com/21-days.html>

------
itsnotvalid
"I was already pretty dead set on learning a functional language (either
Python or Ruby)"

Did I see something strange here?

~~~
rimantas
He meant javscript. A common typo.

~~~
Jach
Eh? How is Javascript any more functional than Python or Ruby?

------
josephcooney
He said he wanted to learn a functional language, and then listed Python and
Ruby. Weird.

~~~
sahillavingia
There's a joke here I don't get. Care to explain? :D

~~~
Nate75Sanders
Python and Ruby aren't functional languages.

You can write code in them in a functional manner, but for anything more than
toy programs you _likely_ wouldn't.

They're heavily Object-Oriented, but could probably safely be called multi-
paradigm. Not just "functional", though.

Functional languages are Haskell, ML, others, where you express computation by
composing functions (in the mathematical sense). You make lots of copies and
you don't modify state directly like procedural and OO languages do where you
modify state a lot.

~~~
meric
I remember it took me a dozen times of carefully reading explanations like
this before I finally got what "functional" meant... I'll try to provide an
explanation my former self would have easily got.

    
    
      lambda x: x+1 
    

If you only program with lambda's like these, your program is functional.

    
    
      def dosomething(x):
          y = x + 3 # y is a global variable
          return x + 1
    

As soon as you have a function like this, your program is no longer 100%
functional.

The dosomething function modified `state` when it changed a global variable.
Another function that modifies state is "print()". Generally any function that
returns nothing is almost certainly going to modify state outside of it.
(Otherwise what is the function for?)

State is memory that is not `local` to the function itself.

    
    
      def dosomething(x):
          y = x + 3 # y is a local variable
          return x + 1
    

The dosomething function here is functional, because the only `state` it
modified was local to the function.

There you have it.

~~~
mixu
Even more simply - are you writing code for a von Neumann architecture
(<http://en.wikipedia.org/wiki/Von_Neumann_architecture> ), or something more
abstract?

To my understanding the issue is not whether "state" has side effects (e.g.
your global vs. local example), but rather whether there is any concept of
"state" (e.g. shuffling stuff from one memory slot to another).

My experience is from Prolog, where the statement "X is X + 1" results in an
error, because once unified, the variable X cannot be modified - X is not a
memory slot. Once you try to let go of the idea of a machine with memory
slots, alternative-paradigm programming gets a little bit easier. Of course in
practice state is often needed, so it often gets added through some mechanism.

~~~
meric
That's a good explanation.

My explanation is catered to people accustomed to the von Neumann
architecture, however. :)

------
torme
Completely unrelated to your write up but theres a bug. In FF if I back up and
resubmit it doesn't update to the new text. I still see my first submission.

~~~
sahillavingia
Ah yes, I randomly generate a permalink on load of the page, so it uses the
old permalink, hence why it loads the first submission. Any ideas on how to
change this?

~~~
torme
I guess just generate the permalink in the action and redirect to that instead
of having it in the form itself.

Something like:

Form: /reworder/generate

Action: Generates text, creates permalink and then redirects user to that
permalink.

In the web world this pattern is common, called redirect-after-post. I'm not
sure if thats much help, I've only used python in the context of the Pylons
framework (and have only a few days experience with it at that). If you need
more guidance let me know and I'll try and clarify.

edit: Link to redirect after post:
<http://en.wikipedia.org/wiki/Post/Redirect/Get>

edit2: I should also say this is a pretty sweet project, sorry if I just
listed criticisms.

~~~
sahillavingia
Of course not, I love criticisms. How else do I improve? I'll implement that
ASAP.

------
smoody
"App engine is fast and awesome, right now. However, if your site gets really
popular, you may consider moving off of it."

Perhaps you can explain why you believe this to be true? I thought that the
strength of App Engine is that you can stay on it no matter how popular your
app gets.

~~~
sahillavingia
App engine doesn't allow certain features, like subdomains for each user, and
non-www. URLs. Some other things too, that I probably don't even know about
yet.

~~~
detst
While I agree that there are limitations with App Engine, I disagree with your
two examples; not only are these possible, I think they have a nice solution
on App Engine.

1\. Wildcard subdomains and multi-tenancy seem to be a nice solution to
"subdomains for each user".

2\. Unless by "non-www. URLs" you mean naked domains, that is also possible;
both explicitly defined and with wildcard subdomains.

Maybe I'm misinterpreting you though.

------
jscore
Traceback (most recent call last): File
"/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py",
line 513, in __call__ handler.post(*groups) File
"/base/data/home/apps/reworder/1.345779356045891791/reworder.py", line 140, in
post synonym = synonym_for_word(stripped_word, tag) File
"/base/data/home/apps/reworder/1.345779356045891791/reworder.py", line 201, in
synonym_for_word return result.get(word_type)['syn'][0] KeyError: 'syn'

------
StanDarsh
Awesome story. Thank you very much for the Stanford links.

------
jacquesm
Hey, weren't you supposed to be a designer :) That's pretty quick to go from 0
to launch in 5 days in an unknown language.

Congratulations!

~~~
sahillavingia
Designer, developer, coder, sleep-deprived. I'm a dude of many properties! :)

------
paulbaumgart
Any input containing a forward slash results in a ValueError.

------
davidj
if anyone cares, rephrasing engines are used to create splogs for SEO

------
dgreensp
Breaks on apostrophes.

