Try Nirvana. It's web-based, rather than desktop-based like Things, but is very similar in UI, and, since it's online, can be accessed from anywhere. As someone who simultaneously uses PCs and Macs, I long since ditched Things for Nirvana. 

Is there something like Things for Windows?
I am creating a small Node.js application, but I think the file becomes unreadable. I am certain the file can be split into some better managable file.

Here is my app.js

var sio          = require('socket.io'),
    fs           = require('fs'),
    express      = require('express'),
    connect      = require('connect'),
    MemoryStore  = express.session.MemoryStore,
    app          = express.createServer('http://mysite.dev'),
    sessionStore = new MemoryStore(),
    parseCookie  = connect.utils.parseCookie,
    Session      = connect.middleware.session.Session
    db           = require('mongoose').connect('mongodb://localhost/dev_db'),
    Common       = {
        users: require('./server/models/user').User
    };

app.configure(function () {
    app.use(express.cookieParser());
    app.use(express.session({
        store: sessionStore,
        secret: 'secret',
        key: 'express.sid'
    }));
    app.get('*', function (req, res) {
        res.sendfile(__dirname + '/assets/tmpl/index.html');
    });
});

app.listen(8008);
var io = sio.listen(app);

io.configure(function () {
    io.set('transports', ['websocket']);
});
io.set('authorization', function (data, accept) {
    if (data.headers.cookie) {
        data.cookie = parseCookie(data.headers.cookie);
        data.sessionID = data.cookie['express.sid'];
        data.sessionStore = sessionStore;
        sessionStore.get(data.sessionID, function (err, session) {
            if (err || !session) {
                accept('Error', false);
            } else {
                data.session = new Session(data, session);
                accept(null, true);
            }
        });
    } else {
        return accept('No cookie transmitted.', false);
    }
});

var create = function (socket, signature) {
    var e = event('create', signature), data = [];
    socket.emit(e, {id : 1});
};

var read = function (socket, signature) {
    var e = event('read', signature);
    if(signature.endPoint){
        Common[signature.endPoint][signature.cb](socket, signature.ctx, function(err, data){
            if(err) throw err;
            socket.emit(e, data);
        })
    }

};

var update = function (socket, signature) {
    var e = event('update', signature), data = [];
    socket.emit(e, {success : true});
};

var destroy = function (socket, signature) {
    var e = event('delete', signature), data = [];
    socket.emit(e, {success : true});
};

// creates the event to push to listening clients
var event = function (operation, sig) {
    var e = operation + ':';
    e += sig.endPoint;
    if (sig.cb) e += (':' + sig.cb);
    if (sig.ctx) e += (':' + sig.ctx);

    return e;
};

io.sockets.on('connection', function (socket) {

    var hs = socket.handshake;
    console.log('A socket with sessionID ' + hs.sessionID + ' connected!');
    // setup an inteval that will keep our session fresh
    var intervalID = setInterval(function () {
        hs.session.reload( function () {
            hs.session.touch().save();
        });
    }, 60 * 1000);

    socket.on('init', function(data){
        if(hs.session.userdata){
            fs.readFile(__dirname + '/assets/tmpl/user/dashboard.html', 'utf8', function(err, html){
                if(err) throw err;
                socket.emit('init', {callback: 'dashboard', tmpl: html});
            });
        }else{
            fs.readFile(__dirname + '/assets/tmpl/user/login.html', 'utf8', function(err, html){
                if(err) throw err;
                socket.emit('init', {callback: 'login', tmpl: html});
            });
        }
    });

    socket.on('create', function (data) {
        create(socket, data.signature);
    });
    socket.on('read', function (data) {
        console.log(hs.session);
        read(socket, data.signature);
    });
    socket.on('update', function (data) {
        update(socket, data.signature);
    });
    socket.on('delete', function (data) {
        destroy(socket, data.signature);
    });

    socket.on('disconnect', function () {
        console.log('A socket with sessionID ' + hs.sessionID + ' disconnected!');
        clearInterval(intervalID);
    });
});

