• Bestpractices по ООП и паттернам в js?

    @bromzh
    Drugs-driven development
    Вопрос из серии "почему в функциональных языках нет циклов и переменных и как с этим жить". Так вот, жить можно вполне хорошо. Просто немного по-другому.
    Советую изучить, что же такое ООП и какое оно бывает. За пару минут можно найти инфу, что в жаваскрипте ООП - прототипное, а в питоне "классоориентированое". Т.е. в первом всё есть объект, и создавать новые объекты можно только клонируя основной объект, все методы и поля ищутся сперва у объекта, а потом у всех его прототипов. Во втором случае есть разделение на классы и объекты - экземпляры этих классов. Там диспетчеризация устроена по-другому: методы и поля ищутся у класса, а потом у всех его предков.
    И обходиться без наследования и метаклассов можно довольно легко, если знать, для чего же вообще нужно наследование и метаклассы. Метакласс позволяет манипулировать создаваемым классом на уровне его создания. Т.е. в питоне есть 2 понятия: класс и его экземпляр. В конструкторе класса можно определить поведение создаваемых экземпляров (через __new__ и __init__). Чтобы изменить поведение самого класса (а не его экземпляра) и нужны метаклассы: там, в функциях __init__ и __new__ можно переопределить поведение при создании класса. Так как в жаваскрипте такого разделения нет, то и отпадает само понятие метакласса: каждый объект создаётся путём клонирования от базового объекта (Object в js, хотя можно клонировать и любой другой объект: Array, Function, твой собственный). Такая же фигня и для наследования: там ты просто указываешь, какие поля могут выступать в качестве прототипов для всех "дочерних" объектов, это когда пишешь MyClass.prototype.someMethod = function(args) { ... }. В данном случае, someMethod будет сперва искаться среди самого объекта. Если там такого нет, то ищется в прототипе, т.е. в MyClass. Ну "классы" там объявляются функциями, потому что синтаксис не предусматривает создание класса. Да и то, функция-класс - просто синтаксический сахар: при вызове оператора new MyClass эта функция исполняется и возвращает копию объекта Object, над которой применили некие операции (которые ты как раз и описываешь в ней). Для каждой функции создаётся свой локальный контекст, который хранится в переменной this. Ты можешь в функции-классе описать, какие поля добавить в this, и она вернёт тебе как раз-таки этот изменённый this. Вот в lua нет даже оператора new, и ничего, вполне удобное ООП.

    У каждого подхода есть и плюсы и минусы. Мне удобно писать в обоих стилях. Единственное, могут возникнуть проблемы, когда в классе вытаешься присвоить полю какую-то функцию (callback). This внутри этого колбека будет иметь локальный контекст этой функции, а объекта, в котором находится это поле. На помощь приходит функция bind.

    P.S. Важно понимать, что функции являются объектами (в обоих языках). Но в js использование функций как переменных встречается гораздо чаще. Поэтому, строго говоря, нет никаких методов и полей в js. У объекта просто есть члены, которые могут быть как простыми данными и объектами, так и функциями. Собственно, для питона это тоже верно, ведь сами классы тоже являются объектами (экземпляры типа type). Просто там есть 2 понятия, как бы двухуровневая система. Ну и там куда реже члену объекта присваивают функцию, нежели в JS.
    Ответ написан
    1 комментарий
  • Как выполнить запрос в базу на ajax?

    @bromzh
    Drugs-driven development
    Задержку по времени в синхронном коде вставлять нельзя. будет тормозить всё приложение (оно же однопоточное). Делай задержку в асинхронном режиме. Тебе надо написать функцию, которая будет выполнять запрос и проверять, заполнилась ли переменная нужным значением. Если да - то возвращай его, если нет - делай задержку и повторяй. ПХП я не знаю (и как там работать с корутинами тоже). Ты сам почитай, например, вот это. Я приведу пример, как это можно сделать на питоне с пояснениями, на ПХП сам перепиши. Итак:
    import asyncio  # модуль, который позволяет работать в асинхронном режиме
    import random
    
    # "сообщаем", что функция получения данных будет исполняться как сопрограмма
    @asyncio.coroutine
    def fetch_data():
        data = 0
        # Для примера, будем запрашивать данные, пока не выпадет 6-ка.
        # в реале, вместо получения рандома, ты должен делать запрос к БД
        while not data == 6: 
            print(data)
            data = random.randint(0, 10)  # вот тут делай запрос к БД и заполняй твою переменную
            yield from asyncio.sleep(3.0)  # асинхронная задержка, она не будет блокировать приложение
        return data  # когда вышли из цикла, в переменной data будет только нужная инфа
    
    # эта функция тоже будет исполняться как сопрограмма. без этого декоратора невозможно получать асинхронно данные через yield from
    @asyncio.coroutine
    def test():
        # получаем данные асинхронно
        # переменная data заполнится только тогда, когда в функции fetch_data выпадет 6,
        # она выйдет из цикла и вернёт значение
        data = yield from fetch_data()
        print('Bingo!', data)
        loop.stop()  # когда получили данные, останавливаем асинхронный цикл
        # ты не должен останавливать, чтобы каждый раз не запускать цикл при получении данных
        # ты должен просто вернуть данные клиенту    
        
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()  # создаём цикл
        asyncio.async(test())  # асинхронно запускаем функцию
        # тебе это надо делать при каждом запросе на какой-то УРЛ
        # По-сути, в обработчике УРЛ ты должен просто вызывать функцию test, 
        # а она уже отошлёт данные клиенту
        loop.run_forever()  # запускаем бесконечный асинхронный цикл
        loop.close()  
        # если он завершится (у меня он завершается, когда получена 6-ка), надо закрыть цикл


    Ну или вариант попроще, на клиенте создай функцию, которая будет отправлять AJAX-запрос к серверу и ставь таймер в 3 секунды. Когда вернётся непустое значение, тормози таймер.
    Ответ написан
    Комментировать
  • Возможна ли загрузка части JSON с jQuery?

    @bromzh
    Drugs-driven development
    Есть несколько основных варианта организовать вывод части данных.
    Вариант №1 - количество элементов на 1-й странице и номер страницы. Это самый негибкий вариант.
    Вариант №2 - сдвиг и количество. Задаёшь текущий сдвиг и количество элементов.
    Вариант №3 - от и до. Задаёшь, номер начального и конечного элемента.
    Пример. Надо получить данные для 3-й страницы.
    Для варианта №1 значения будут такие items_per_page = 25; page = 3
    Для варианта №2 значения будут такие shift = 50; count = 25
    Для варианта №2 значения будут такие from = 50; to = 75

    Как это реализовать на практике. (Привожу примеры на питоне и для 2-го варианта)
    Вариант на сервере
    Я не знаю, какой у тебя язык на серваке и какие технологии ты используешь. Но обычно, если используется ORM, то он позволяет получать записи из БД в определённом промежутке, либо постранично. Тогда код будет таким:
    @app.route("/api/items/")
    def items():
        shift = request.get("shift")
        count = request.get("count")
        return Item.objects.all().from(shift).to(shift + count)

    Ну а из клиента делай ajax-запрос на этот урл с нужными ГЕТ-параметрами, т.е. урл будет выглядеть так: /api/items/?shift=50&count=25. На нажатие кнопки с номером страницы вешай функцию, которая узнает номер страницы и сформирует соотв. запрос

    Вариант - на клиенте
    Сервер отдаёт сразу все элементы. На клиенте используй angular/knockout/etc. Данные сохраняются в массив моделей (модель соответствует информации для каждой item). Нажатие кнопки с номером страницы не запрашивает данные с серва, а загружает модели выбранного фреймворка в определённом промежутке.

    Если ты скажешь, что используешь на сервере и какие фреймворки используешь на клиенте, я смогу написать к выходным гист с работающим примером для твоего языка.
    Ответ написан
    Комментировать
  • Как проверить, что ошибок при компиляции нет?

    @bromzh
    Drugs-driven development
    Просто используй Maven, Gradle или им подобные. Это не только система сборки, это инструменты для полного управление жизненным циклом проекта: автозагрузка зависимостей, сборка, упаковка, деплой, куча плагинов для разных нужд.
    В саблайме для билда укажи строку "maven clean compile run:run" или "maven clean package run:run", вариантов много. Ну или используй IDE, для крупных проектов (тем более на java) саблайм плохо подходит.
    Ответ написан
    1 комментарий
  • Почему while только тогда, когда нет нужды во втором итеративном свойстве?

    @bromzh
    Drugs-driven development
    Просто цикл for выглядит более ясно и понятно, если надо перебрать некую коллекцию. В случае while можно напортачить с изменением счётчика. While обычно используют, если критерий выхода из цикла - некое логическое значение. А for - если идёт итерация по коллекции (массив или объект).
    Ответ написан
  • Как браузеру скачать файл, если веб-сервис отдает его только при наличии в хедере запроса авторизационной информации?

    @bromzh
    Drugs-driven development
    Вот тут пример отправки:
    var bytesToSend = [253, 0, 128, 1],
        bytesToSendCount = bytesToSend.length;
    
    var bytesArray = new Uint8Array(bytesToSendCount);
    for (var i = 0, l = bytesToSendCount; i < l; i++) {
      bytesArray[i] = bytesToSend[i];
    }
    
    $.ajax({
       url: '%your_service_url%',
       type: 'POST',
       contentType: 'application/octet-stream',  
       data: bytesArray,
       processData: false
    });

    Сделай так, только наоборот.
    Ответ написан
    1 комментарий
  • Какой существует инструментарий для рисования\работы красивого графа в браузере?

    @bromzh
    Drugs-driven development
    eax.me/dracula
    Как в JavaScript построить графы,блок схемы и потокы данных ?

    Ещё вариант - поднять сервер Python Notebook и рисовать графы в matplotlib и других инструментах.
    Ответ написан
    Комментировать
  • Как сделать инфо панель как на Хабре?

    @bromzh
    Drugs-driven development
    Для дочерних элементов прописываешь либо display: inline-blockлибо float: left
    Если делаешь вариант с float, то надо ещё делать clearfix, чтобы поток очистить.
    Ответ написан
    Комментировать
  • Как правильно организовать верстку контента под ajax?

    @bromzh
    Drugs-driven development
    Если надо сделать и забыть - то пофиг, и так сойдёт.
    Если это поддерживаться и развиваться будет, то освой Knockout/Angular/etc. Делаешь привязку к данным через AJAX, на клиенте сохраняешь данные в ViewModel (или ему подобное), клики связываешь с выводом попапов.
    Вот пример на Knockout:
    <script type="text/javascript">
        function PopupModel(data) {
            var self = this;
            ko.mapping.fromJS(data, {}, self);
        }
        function ViewModel(data) {
            var self = this;
            var activePopup = ko.observable(null);
            ko.mapping.fromJS(data, {}, self);
            var popUpChooser = function(popupId) {
                $.getJSON('/api/popup/' + popupId, function(data) {
                    // Получаем инфу для одного попапа
                    // JSON:
                    // {
                    //     'id': '1',
                    //     'name': 'foo',
                    //     'email': 'foo@example.com'
                    // }
                    self.activePopup(new PopupModel(data));
                })            
            }
        }
        $(function() {
            $.getJSON('/api/popup/ids/', function(data) { // получаем список Id инфы для попапов
                // JSON такого вида: { popupIds: ['1', '2', '3'] }
                ko.applyBindings(new ViewModel(data));
            });
        });
    </script>
    <div data-bind="foreach: popupsIds">
        <input type="radio" data-bind="attr: {value: $data}"/>
    </div>
    <div class="popup" data-bind="if: activePopUp"> // отображаем, только если есть активный попап
        <div data-bind="text: activePopup().name"></div>
        <div data-bind="text: activePopup().email"></div>
    </div>

    Можно вообще сразу загружать всю инфу про попапы, код немного поменяется, но смысл тот же.
    Ответ написан
  • Как включить в свое приложение измененные исходные тексты, распространяемые под BSD-лицензией?

    @bromzh
    Drugs-driven development
    Просто оставь имена авторов в изменённых файлах и добавь своё имя. В лицензии всего проекта укажи, что некоторые части лицензируются под BSD, а в остальном апач. Приложи текст каждой лицензии в проект. В голове каждого файла указывай коротко, под какой лицензией он распространяется.
    Ну а вообще, это не GPL, эти лицухи очень либеральны. Главное не стирай копирайты.
    Ответ написан
    Комментировать
  • Как реализовать систему эффектов (модификаторов) накладываемых на игрока?

    @bromzh
    Drugs-driven development
    Так как ты не сказал, на каком языке пишешь, скину код на питоне:
    class Effect:
    
        def __init__(self, name, mods):
            self.name = name
            self.mods = mods
            # mods - это словарь с модификаторами
            # ключ - имя поля в классе User
            # значение - функция, которая принимает экземпляр класса User и промежуточное значение поля
            # а возвращает изменённое значение поля
    
    
    class User:
    
        def __init__(self, name, strength, agility):
            # Инициируем начальные значения
            self.name = name
            self.strength = strength
            self.health = strength * 100
            self.agility = agility
            self.effects = list()
    
        # в самом классе храним только независимые значения
        # но любой доступ к параметрам должен идти через геттер
        # для каждого необходимого параметра создаём функцию-геттер
        # которая будет учитывать применение эффектов
        # можно вместо этого использовать @property
        def get_strength(self):
            strength = self.strength
            for effect in self.effects:
                if effect.mods.get('strength'):
                    strength = effect.mods['strength'](strength, self)  # вызываем функцию - модификатор
            return strength
    
        def get_agility(self):
            agility = self.agility
            for effect in self.effects:
                if effect.mods.get('agility'):
                    agility = effect.mods['agility'](agility, self)  # вызываем функцию - модификатор
            return agility
    
        def get_health(self):
            health = self.health
            for effect in self.effects:
                if effect.mods.get('health'):
                    health = effect.mods['health'](health, self)  # вызываем функцию - модификатор
            return health
    
        # Это зависимый параметр
        def get_max_health(self):
            max_health = self.get_strength() * 100  # первоначальное значение вычисляется на основе силы
            for effect in self.effects:
                if effect.mods.get('max_health'):
                    max_health = effect.mods['max_health'](max_health, self)  # вызываем функцию - модификатор
            return max_health
    
    
    if __name__ == '__main__':
        foo = User('Foo', 10, 10)
        god_strength = Effect('God strength', {
            'strength': lambda s, u: s + 10
        })
    
        def _life_power_func(value, user):
            return value + 100
    
        life_power = Effect('Life Power', {
            'max_health': _life_power_func
        })
    
        def _extra_agility_func(value, user):
            return value + 10
    
        # этот эффект влияет сразу на 2 параметра
        extra_agility = Effect('Extra agility', {
            'agility': _extra_agility_func,
            'max_health': lambda h, u: h - 400
        })
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])
        foo.effects.append(god_strength)
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])
        foo.effects.append(life_power)
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])
        foo.effects.append(extra_agility)
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])

    Результат:
    10 1000 1000 10 []
    20 2000 1000 10 ['God strength']
    20 2100 1000 10 ['God strength', 'Life Power']
    20 1700 1000 20 ['God strength', 'Life Power', 'Extra agility']
    Ответ написан
    3 комментария
  • Что входит в обязанности "тонкого контроллера" и как при нем происходит связь вида с моделью?

    @bromzh
    Drugs-driven development
    Но в объектно-ориентированном программировании используется активная модель MVC, где модель — это не только совокупность кода доступа к данным и СУБД, но и вся бизнес-логика. Следует отметить возможность модели инкапсулировать в себе другие модели. В свою очередь, контроллеры представляют собой лишь элементы системы, в чьи непосредственные обязанности входит приём данных из запроса и передача их другим элементам системы. Только в этом случае контроллер становится «тонким» и выполняет исключительно функцию связующего звена (glue layer) между отдельными компонентами системы.


    Как это можно было не заметить на википедии?
    Ответ написан
  • Практическая часть изучения ЯП и web технологий?

    @bromzh
    Drugs-driven development
    Сперва реши, какая часть тебе больше нравится - фронтенд или бэкенд. Знать придётся всё, но лучше углубиться в одно направление.
    Если выбрал первое - бери готовый сайт, попытайся сверстать так же, без особого подглядывания в исходники. Потом добавляй интерактив на страницу. Потом бери какой-нибудь mvvm-фреймворк на JS и сделай одностраничное приложение. Не забывай учиться, как взаимодействовать с серверной частью. Инструменты: препроцессоры для CSS - Less/SCSS, библиотеки для JS - jQuery, Knockout, Angular, etc.
    Если хочешь заниматься бэкендом на питоне - бери и изучай какой-нибудь фреймворк, для начала подойдёт Django. Сперва делай сайт, типа бложека, новостного или магазина. Потом добавляй всякие плюшки - пагинацию, RSS, затем делай REST API, переделай сайт, чтобы он мог подгружать данные без перезагрузки страниц. После этого изучи другой фреймворк , сделай тоже самое на нём. Потом изучай асинхронные штуки, прикрути к твоему сайту чатик. Инструменты - Django/Flask как обычные веб-фреймворки, Twisted/Tornado/asyncio для асинхронных штук. ZeroMQ (или другие MQ), Celery для общения между приложениями. Неплохо научиться работать с разными видами БД: как SQL, так и NoSQL.

    Но в реальной жизни хрен знает, что тебе пригодится для работы.
    Ответ написан
    Комментировать
  • Несколько вопросов по Scheme и языкам функционального программирования?

    @bromzh
    Drugs-driven development
    Смотря какую цель ты ставишь перед собой. Обычно подбирают инструмент под задачу, а не наоборот. Изучать ради изучения - не самая лучшая идея. Но знать основы функциональщины никогда не повредит.
    Да и важно понимать, что в функциональном стиле можно писать практически на любых языках, а не только на чисто функциональных.

    1) Схема очень проста, но непривычна. Прочитай SICP, отличная книга по программированию в целом.
    2) Почти никаких. Так уж вышло, что она не особо популярна в прикладных областях. Ну а в самом Racket можно выбирать разные диалекты, посмотри там.
    3) Эрланг, в силу устройства самой платформы, отлично подходит для быстрых асинхронных сетевых приложений (и никакого коллбечного ада). Для скалы есть хорошие веб-фреймворки: Play 2, Lift, etc. Для кложы не так много, но последние 2 - это JVM, соответственно, можно использовать многие Java-либы.
    4) Питон никуда не ориентирован. Что мешает комбинировать разные парадигмы? Просто в питоне всё есть объект. Это облегчает ООП, да. Многие типы данных там мутабельны. Но и функциональный подход там тоже часто применяют (декораторы, например - частое явление). Map'в и reduce'ы тоже присутствуют, плюс, есть целый пакет functools. И numpy.

    В общем, почитай SICP =)
    Ответ написан
    2 комментария
  • Верна ли форма регистрации на python?

    @bromzh
    Drugs-driven development
    Самый простой способ - это использовать OpenID для аутентификации. После успешного ответа сервера тебе приходят некоторые данные пользователя, но их хранить не обязательно. БД можно не использовать, просто храни куку некоторое время.
    Ну а если нужно хранить какие-то дополнительные данные - храни их в классовом поле некого класса.
    class User(object):
        clients = set()  # можно использовать и список
                         # можно и словарь, чтобы быстро получать 
                         # конкретного пользователя по какому-то ключу
    
        def __init__(self, user=None, root=None, admin=None, moderator=None, **kwargs):
            self.user = user
            self.root = root
            self.admin = admin
            self.moderator = moderator
            # Записываем в класс необходимые поля из kwargs
            self.foo = kwargs.pop('foo', 'default_value')
    
        def auth(self):
            # тут аутентифицируем юзера
            # данные, которые пришли в ответ, можно записать в поля класса
            # после того, как всё записал, делай так:
            self.clients.add(self)  # добавляем подключившегося пользователя
            # Этот массив/сет/словарь будет доступен из любого экземпляра этого класса
            # и из самого класса тоже, например: [print(client) for client in User.clients]
    
    # чтобы хранить данные между перезагрузкой сервера, можно использовать pickle:
    import pickle
    with open('foo.pickle', 'w') as f:
        pickle.dump(f, User.clients)
    # загружать так же:
    with open('foo.pickle'. 'r') as f:
        User.clients = pickle.load(f)

    Вот простой пример, чтобы было яснее:
    >>> class A(object):
    ...     c = list()
    ...     def __init__(self, **kwargs):
    ...         self.__dict__.update(**kwargs)
    ...     def save(self):
    ...         self.c.append(self)
    ... 
    >>> a = A(a=1, b=2)
    >>> a.save()
    >>> b = A(a=[3, 4], foo={1, 2})
    >>> b.save()
    >>> A.c
    [<__main__.A object at 0x7fd63603d0b8>, <__main__.A object at 0x7fd63603dc18>]
    >>> pickle.dumps(A.c)
    b'\x80\x03]q\x00(c__main__\nA\nq\x01)\x81q\x02}q\x03(X\x01\x00\x00\x00bq\x04K\x02X\x01\x00\x00\x00aq\x05K\x01ubh\x01)\x81q\x06}q\x07(X\x03\x00\x00\x00fooq\x08cbuiltins\nset\nq\t]q\n(K\x01K\x02e\x85q\x0bRq\x0ch\x05]q\r(K\x03K\x04eube.'
    >>> A.c = []
    >>> A.c = pickle.loads(b'\x80\x03]q\x00(c__main__\nA\nq\x01)\x81q\x02}q\x03(X\x01\x00\x00\x00bq\x04K\x02X\x01\x00\x00\x00aq\x05K\x01ubh\x01)\x81q\x06}q\x07(X\x03\x00\x00\x00fooq\x08cbuiltins\nset\nq\t]q\n(K\x01K\x02e\x85q\x0bRq\x0ch\x05]q\r(K\x03K\x04eube.')
    >>> A.c
    [<__main__.A object at 0x7fd63604ca58>, <__main__.A object at 0x7fd63604c908>]
    >>> A.c[0].a
    1
    >>> A.c[1].a
    [3, 4]
    Ответ написан
    Комментировать