Python coding environment
I use PyCharm Professional for Blender add-on development. It has debugging support (the Community edition does not) and limited auto-completion if you create auto-completion files for it with this tool.

Here's a tutorial and a Blender add-on to connect Blender to the PyCharm debugger.

My workflow then is like this:


Create an add-on and enable it in Blender. An add-on is basically a Python package you create inside a new package folder under &lt;version&gt;\scripts\addons.
Edit its code in PyCharm.
Reload the add-on in Blender with F8. This requires the __init__.py of the package to have a specific layout. Here are the bare bones I always use: I added some comments to the end of the lines and left several modules in there as an example (which you'd create accordingly in python code files inside the package directory):

bl_info = {
    "name": "Title as it appears in settings",
    "description": "Smaller description below it",
    "author": "Your name",
    "version": (1, 0, 0), # A tuple of version numbers
    "blender": (2, 75, 0), # The minimum required Blender version
    "location": "File &gt; Import-Export", # Where it will be located. These strings are hard-code in Blender
    "warning": "This add-on is under development.", # A warning with a yellow triangle if you want.
    "wiki_url": "https://github.com/Syroot/io_scene_kcl/wiki", # Link to a wiki
    "tracker_url": "https://github.com/Syroot/io_scene_kcl/issues", # Link to an issue tracker
    "support": "COMMUNITY", # Probably just COMMUNITY since you're not an official developer etc.
    "category": "Import-Export" # Also hardcode
}

# Reload the package modules when reloading add-ons in Blender with F8.
if "bpy" in locals():
    import importlib
    if "log"       in locals(): importlib.reload(log)
    if "binary_io" in locals(): importlib.reload(binary_io)
    if "kcl_file"  in locals(): importlib.reload(kcl_file)
    if "importing" in locals(): importlib.reload(importing)
    if "editing"   in locals(): importlib.reload(editing)
    if "exporting" in locals(): importlib.reload(exporting)

import bpy
from . import log
from . import binary_io
from . import importing
from . import editing
from . import exporting

def register():
    bpy.utils.register_module(__name__)
    # Importing
    bpy.types.INFO_MT_file_import.append(importing.ImportOperator.menu_func_import) # Add menu entry to File &gt; Import
    # Editing
    bpy.types.VIEW3D_MT_edit_mesh_select_similar.append(editing.KclSelectSimilar.menu_func) # Add custom properties to a mesh
    bpy.app.handlers.scene_update_post.append(editing.scene_update_post_handler) # Listen to global Blender-wide events
    # Exporting
    bpy.types.INFO_MT_file_export.append(exporting.ExportOperator.menu_func_export) # Add menu entry to File &gt; Export

def unregister(): # Basically just undo the stuff done in register()
    bpy.utils.unregister_module(__name__)
    # Importing
    bpy.types.INFO_MT_file_import.remove(importing.ImportOperator.menu_func_import)
    # Editing
    bpy.types.VIEW3D_MT_edit_mesh_select_similar.remove(editing.KclSelectSimilar.menu_func)
    bpy.app.handlers.scene_update_post.remove(editing.scene_update_post_handler)
    # Exporting
    bpy.types.INFO_MT_file_export.remove(exporting.ExportOperator.menu_func_export)

# Register the package modules when Blender runs this script.
if __name__ == "__main__":
    register()

Optionally, set breakpoints and connect Blender to the remote debugger of PyCharm.
Call operators the add-on defines, test the stuff it adds.
Fix errors, reload with F8, rinse, repeat.


You can find some samples of add-ons of me in my GitHub repos (check out those named with the io_scene_* name prefix).