6 учебных сайтов для веб-разработчика, по делу и без шелухи

Среди множества сайтов, посвященных веб-разработке в интеренете, есть много отличных справочных пособий, руководств и т.п. В данном обзоре я приведу несколько отличных сайтов, которыми пользуюсь сам. Здесь не будет абсолютно необходимых и известных всем php.netstackoverflow.com и т.п., зато будут, может быть, менее известные сайты, но с большим уклоном не на справочность, а на обучение, и написанных понятным языком без всякой шелухи.

1 W3schools.com

w3schoolsЭтот сайт особенно полезен для начинающих разработчиков. Там коротко и понятно объясняются основные концепции HTML, CSS, JavaScript, PHP, XML и многих других веб-технологий. Более продвинутые разработчики, могут использовать сайт в своей работе как краткую справку в первую очередь по клиентским технологиям: HTML, CSS, JavaScript. Если забыли, какие значения может принимать атрибут определенного тега, если нужно сообразить, как написать сложный CSS-селектор, если нужно проверить, будет ли поддерживать определенное свойство конкретный браузер, то этот сайт будет полезен.

2 Bonsaiden

Отличное краткое онлайн-руководство по ключевым концепциям JavaScript. Хотите понять, как устроены замыкания, на что ссылается this или как используется прототип, то лучшего подспорья не найти. Я бы оценил руководство, как хорошее среднее звено между сайтами для начинающих и сложными статьями или учебниками по узким вопросам.

3 Phptherightway.com

phptherightwayСайт для разработчиков PHP, на котором группой авторитетных программистов собраны лучшие практики и рекомендации по актуальным вопросам. Оформление кода, документирование, доступ к БД, шаблонизация, безопасность, тестирование, кеширование, разные вопросы непосредственно программирования — только некоторые из тем, освещенных там. Сайт достаточно авторитетен, чтобы пользоваться им как руководством, и практики, освещенные там, являются результатом долгих обсуждений и консенсуса в среде разработчиков.

Survive The Deep End: PHP Security

Этот сайт — онлайн книга также о PHP, точнее, о вопросах безопасности в PHP. Коротко и ясно там и про валидацию входных данных, и про кросс-сайтовые атаки, и про инъекции, и про то, как от предусмотреть защиту от возможных атак в коде.

Sourcemaking.com

Паттерны проектирования (в первую очередь PHP), антипаттерны, советы по рефакторингу и учебник по UML — вот что такое этот сайт. Темы раскрыты максимально подробно и понятно. По сути сайт — это полноценный онлайн-учебник по указанным аспектам архитектуры PHP-приложений (вообще, не только PHP, но и C#, Java и т.п., однако веб-разработчику интересен в первую очередь PHP). Для каждого паттерна проектирования есть примеры на PHP.

Use-the-index-luke.com

usetheindexlukeВеб-разработчику приходится работать и с базами данных. Понятно, что по языку SQL существует много ресурсов, а по конкретным СУБД лучше использовать оригинальную документацию, но есть задачи, которые требуют глубокого понимания некоторых механизмов работы СУБД. Этот сайт доступным языком рассказывает об индексах, как они учстроены и как нужно писать и оптимизировать запросы. Это, пожалуй, единственный специализированный сайт такого рода, который нацелен именно на людей, пишущих запросы к БД, а не на системных админинстраторов. Что важно, в статьях много примеров, и каждый пример есть для каждой из следующих СУБД: DB2, MySQL, Oracle, PostgreSQL, SQL Server.

Явное приведение типов в JavaScript

Javascript — язык со слабой типизацией, поэтому возникает много проблем с операторами сравнения из-за неявного приведения типов.

Совет. Использовать оператор строгого равенства === везде, где только можно.

Для явного приведения к одному из трех примитивных типов можно писать так:

Приведение к строке

'' + 5; // === '5'

Приведение к числу

+'5'; // === 5

Приведение к булеву типу

!!'';      // === false
!!'0';     // === true
!!'-1'     // === true
!!true;    // === true

 

 

8 правил применения уменьшительно-ласкательных суффисков в немецком, без которых ни уменьшить, ни обласкать

  1. Уменьшительно-ласкательные суффиксы в немецком используются там же, где и в русском, и слова с ними в большинстве случаев переводятся аналогичными в русском языке. Например, der Tisch = столdas Tischlein = столик.
  2. В литературном немецком есть всего два уменьшительно-ласкательных суффикса: chen и lein. Например, das Brötchen (от das Brot) или das Mäuschen (от die Maus).
  3. В немецких диалектах есть много других подобных суффисков. Например, li в Müsli или el в «Hänsel und Gretel».
  4. Такие суффиксы всегда дают существительное среднего рода, не важно, какой род был у исходного существительного.
  5. Они не изменяются в множественном числе (das Mäuschen — die Mäuschen).
  6. Обычно они добавляют умлаут в корень слова там, где это возможно.
  7. С некоторыми существительными всегда используется только chen, с другими только lein, и со многими можно использовать оба. Определённых правил для запоминания здесь нет.
  8. Есть слова, основная форма которых исторически вышла из употребления, и уменьшительная форма больше не имеет такого значения, однако грамматические правила из пп 4-6 на них распространяются всё равно. Например, девочка = das Mädchen, сказка = das Märchen.

12 вещей, которые нужно знать о классах и прототипах в JavaScript.

Цель этого поста — сказать простыми словами о том, чем объекты и прототипы JavaScript отличаются от обычных для ООП классов и объектов, и почему модель JavaScript является более гибкой, чем классическая для ООП.

  1. В JavaScript всё ведёт себя, как объект.
  2. Абсолютно любая функция может вести себя как конструктор при помощи слова new. constr = new Func ();
  3. Абсолютно любой (даже пустой) объект может выступать в роли прототипа.
  4. Прототип имеется у каждого объекта. Например, для конструктора прототип по умолчанию — это пустой объект.
  5. Прототип — это не что-то особенное, как, например, «класс» в других языках. Это просто обычный объект, без каких-то дополнительных свойств или методов.
  6. Как ведет себя сущность в JavaScript делится между конструктором (любая функция, которая отвечает за создание и инициализацию сущности) и прототипом (задает поведение сущности)
  7. Любое разделяемое между объектами поведение определяется их прототипом. Например, если требуется иметь много объектов с одним и тем же методом, его лучше определить на прототипе.
  8. Ключевое слово this в методе, определенном на прототипе, но используемом на объекте с этим прототипом, ссылается на сам объект.
  9. Свойства и методы, уникальные для объекта, определяются в конструкторе.
  10. Любые свойства и методы прототипа доступны непосредственно в объектах, имеющих этот прототип.
  11. Свойства и методы прототипа могут переопределяться в конструкторе или непосредственно на объекте.
  12. Прототипная модель в JavaScript позволяет реализовать классическое наследование и поведение класс-объект в ООП, но также даёт делать более гибкие вещи.

 

Наследование в JavaScript

Как известно, методы «класса» в JavaScript лучше всего определять на прототипе, а свойства — на конструкторе, потому что методы нежелательно дублировать, определяя заново в каждом объекте, а значения свойств должны быть уникальны для каждого объекта.

Как же реализовать наследование?

Концепция наследования через цепь прототипов

Можно реализовать наследование через цепочку прототипов. Объявляются два «класса», прототип «потомка» объявляется как новый объект, созданный вызовом конструктора «родителя». Вот так:

function SuperType(){
}

function SubType(){
}

SubType.prototype = new SuperType();

Такой подход создаёт только две проблемы:

1. Ссылочные значения делятся между всеми «потомками» «родителя».

2. Нельзя передать аргументы конструктору «родителя».

Способ, предложенный в книге JavaScript Allongé:

Берем суперкласс Superclass, объявляем для него пустой прокси-класс:

var SuperclassProxy = function () {
    this.constructor = Subclass;
}
SuperclassProxy.prototype = Superclass.prototype

Далее мы используем конструктор прототипа суперкласса в конструкторе класса-потомка. В качестве прототипа класса-потомка используем конструктор прокси-класса. Сам прокси-класс нужен, чтобы случайно не испортить что-нибудь в суперклассе при вызове его конструктора. Например, если в конструкторе выполняется подключение к БД, то не выполнять его при каждом наследовании.

var Subclass = function () {
    Superclass.prototype.constructor.call(this)
};

Subclass.prototype = new SuperclassProxy();

Далее мы делаем копию объекта (shallow copy) Superclass и дополняем ее методами и свойствами Subclass.

Решение, предложенное в книге Effective JavaScript:

Допустим, у нас есть SuperType, и мы пытаемся создать SubType на его основе.

function SubType(arg1, arg2, arg3) {
     SuperType.call ( this, arg1, arg2, arg3);
     // разные действия в собственно конструкторе SubType
}
SubType.prototype = Object.create(SuperType.prototype); // наследуем прототип

Здесь мы сначала вызываем конструктор SuperType, передавая туда все требуемые аргументы, а в качестве приёмника будет SubType.

Затем наследуем прототип SuperType.

 

«Пропаганда» Жака Эллюля. Глава 3. Тезисы.

Третья глава посвящена необходимости пропаганды как для государства, так и для отдельной личности.

  1. Пропаганда государству нужна, чтобы нивелировать пропагандистское давление других стран. Это некий механизм психологической защиты граждан от влияния извне.
  2. Также пропаганда нужна для функционирования государственных институтов, например, армии, убеждая людей жертвовать личными интересами ради «высших целей» (в частности, поражение Франции во Второй мировой во многом было обусловлено бестолковой пропагандой и нежеланием воевать).

  3. В демократических либеральных государствах власть очень зависит от общественного мнения, но общественное мнение изменчиво и часто нерационально, поэтому следовать за ним вслепую губительно для государства. Выход — формировать общественное мнение под конкретные рациональные цели. Пропаганда здесь как инструмент.

  4. Для отдельной личности, живущей в супер-стрессовых условиях современности, отсутствие простого объяснения сложного устройства мира ведет к психологическому дискомфорту. Пропаганда в этом плане заменяет человеку религию и дает чувство уверенности и безопасности.

  5. Пропаганда формирует чувство идентичности, принадлежности к группе, что делает человека менее одиноким (а он всегда одинок в массовых обществах современности).

  6. Пропаганда дает объяснение тем вещам, которые иначе вели бы к внутренним конфликтам в человеке. Например, ухудшение экономической ситуации, которое ведет к ухудшению стандартов жизни индивида, ведет к внутреннему конфликту, потому что ему становится хуже, но исправить ситуацию он не в состоянии, к тому же истинные причины ухудшения либо непонятны, либо они такие, на которые он не может влиять. Если ему, например, объяснить, что во всем виноват внутренний или внешний враг, и что нужно потерпеть ради «светлого будущего», то это поможет заглушить его внутренний конфликт.

  7. Пропаганда даёт человеку чувство причастности к важным для него решениям и процессам в государстве, на которые на самом деле он никак влиять не может. Часто правительства профессионально подают свои собственные решения как «волю народа».

  8. Пропаганда дает оправдание проявлению низменных чувств человека. Как сказал автор книги: «Практически каждый мечтает убить своего соседа». Однако, общество построено так, что большинство граждан боится последствий своих насильственных или аморальных действий. Однако, если их проступки будут оправданы, а тем более поощрены, то это привлечёт таких людей. В частности, во время Второй мировой так писались доносы на евреев и так находились мучители и истязатели невинных.

Предыдущая часть                                                               Следующая часть

Анализ запросов в PostgreSQL. Часть 1. Работа с анализатором запросов.

С помощью анализатора запросов SQL мы можем посмотреть, как именно наш запрос обрабатывается СУБД. К сожалению, знания разработчиков часто ограничены, чтобы полноценно использовать полученные данные. Попробуем разобраться, что к чему.

Выполнить запрос с его анализом можно с помощью EXPLAIN. Вот пример запроса и результат его выполнения:

EXPLAIN SELECT * FROM foo WHERE i = 4;

                         QUERY PLAN
--------------------------------------------------------------
 Index Scan using fi on foo  (cost=0.00..5.98 rows=1 width=4)
   Index Cond: (i = 4)
(2 rows)

Как видим, план выпонения запроса включает только одну условную операцию, сканирование индекса.

Не каждый разберётся даже в таком тексте с первого взгляда, хотя обычно такие тексты занимают несколько десятков, а то и сотен строк. Тут на помощь приходят визуализаторы, например, встроенный GUI анализатора для SQL Manager for PostgreSQL (EMS). Вот в каком виде она выдает результат:

SQL Manager

Есть сайт explain.depesz.com/, куда можно скопипастить результат EXPLAIN, и получить такую картинку:

explain SQL visually

Также на сайте можно посмотреть статистику по использованию различных операций в запросе и по обращениям к различным таблицам, из чего сразу можно понять, когда с запросом что-то не так:

2015-07-07_110432

Вернёмся к нашему изначальному запросу.

EXPLAIN SELECT * FROM foo WHERE i = 4;

                         QUERY PLAN
--------------------------------------------------------------
 Index Scan using fi on foo  (cost=0.00..5.98 rows=1 width=4)
   Index Cond: (i = 4)
(2 rows)

cost показывает относительные затраты на выполнение операции. Важно, что это не секунды, а просто некая величина, которая поможет оценить затраты на операцию относительно других операций в запросе;

rows — количество возвращаемых в ходе операции строк;

width — средний размер одной строки в байтах.

Важно понимать, что это не актуальные данные, а то, как планировщик оценивает запрос без его фактического выполнения.

Чтобы получить план выполнения запроса на реальных данных, нужно выполнить его с параметром ANALYZE (Внимание! Если это не SELECT-запрос, то вы можете испортить свои данные, используйте ROLLBACK):

EXPLAIN ANALYZE SELECT * FROM foo WHERE i = 4;

При этом в дополнение к старым выводятся новые данные:

actual time — реальное время в миллисекундах, затраченное для получения первой строки и всех строк соответственно;
rows — реальное количество строк, полученных при выполнении операции;
loops — сколько раз операция выполнялась;
total runtime — общее время выполнения запроса.

Подзапросы

В выводе анализатора запросов могут присутствовать такие ключевые слова как SubPlan, Subquery Scan и InitPlan. Они обозначают подзапросы. SubPlan означает подзапрос, в котором есть ссылки на основной запрос, а InitPlan — подзапрос, у которого нет таких ссылок. Subquery Scan — примерно то же самое, но применяется к подзапросам, входящим в UNION. Все эти операции являются сугубо техническими, на них при анализе запроса можно особо не обращать внимания.

В следующих частях будут освещены основные операции доступа при выполнении запроса и операции объединения, сортировки, группировки и т.д.

 

Мегабайт или мебибайт. Сколько байт в мегабайте?

Как известно из школьного курса математики, кило = 1000, мега = 1 000 000, а гига = 1 000 000 000, и т.д.

Как известно из школьного курса информатики, килобайт = 1024 байт, мегабайт = 1024 килобайта и т.д.

Где-то здесь зарылась несправедливость. Все больше мировые стандарты описывают мегабайт как 1000 байт. Международная электротехническая комиссия в 1998 году решила ввести новые единицы для описания двоичной природы информации. Так повились кибибайт, мебибайт, гибибайт и т.д. «би» здесь означает «бинарный» (двоичный). Теперь 1 кибибайт = 1024 байт, но 1 килобайт = строго 1000 байт.

kB, MB, GB — обозначения для килобайта, мегабайта, гигабайта

KiB, MiB, GiB — обозначения для кибибайта, мебибайта, гибибайта

Несмотря на то, что данные условные обозначения и единицы измерения находят всё большее применение в международных стандартах, есть ещё отдельные стандарты, где килобайт всё ещё равен 1024 байтам. Например, стнадрты для емкостной памяти от JEDEC (ассоциации инженеров, специализирующихся в области электронных устройств). Надеюсь, в ближайшем будущем неопределённости в использовании количественных приставок больше не останется.

Как отличить примитивное значение от объекта в JavaScript

Как известно, в JavaScript существуют примитивные типы, такие как число, строка или булев, и для них имеются соответствующие им объекты типа Number, String, Boolean, у которых есть методы для работы с этими типами, например, методы обработки строк… Если вы попытаетесь применить функцию к примитивному типу, например:

var str = "How are you doing today?";
var res = str.split(" ");

то в данном случае когда к обычной строке str мы применяем метод split, то JavaScript находит подходящий тип объекта, в данном случае это String, создает новый объект с помощью new String («How are you doing today?»); и применяет к нему функцию split.

При этом часто возникает проблема при сравнении двух значений, потому что str === new String (str) выдаст false. Также, если, к примеру, строка » в условии выдаст false, то new String (»)  уже выдаст true. К счастью, так же, как JavaScript автоматически создает объект из примитива, он способен и на обратное. Если мы вызовем конструктор для объекта, замещающего соответствующий примитивный тип, и передадим ему сам объект, то получим значение изначального примитивного типа.

То есть,

String(new String("How are you doing today?")) === "How are you doing today?"

выдаст true, поскольку левая часть выражения возвращает обычную строку.

Это свойство конструктора можно использовать для гарантированного получения примитивных типов с помощью подобной функции:

var getPrimitive = function (sourceValue) {
    return sourceValue.constructor(sourceValue)
}

Не важно, что будет на входе этой функции, примитивное значение или объект, на выходе мы всегда получим примитив.

Например,

getPrimitive ("Привет"); // выдаст обычную строку "Привет"
getPrimitive (new String ("Привет")); // также обычную строку "Привет"

getPrimitive (new String ("Привет"))==="Привет"; выдаст true

Мемоизация в JavaScript

Иногда наши рекурсивные или часто вызываемые функции очень сильно «тормозят» выполнение программы, потому что результаты промежуточных вычислений нигде не сохраняются, а вычисляются заново. Решить проблему может мемоизация.

Из википедии:

Мемоизация — сохранение результатов выполнения функций для предотвращения повторных вычислений. Это один из способов оптимизации, применяемый для увеличения скорости выполнения компьютерных программ. Перед вызовом функции проверяется, вызывалась ли функция ранее: если не вызывалась, функция вызывается и результат её выполнения сохраняется; если вызывалась, используется сохранённый результат.

Классическим примером для иллюстрации является функция, вычисляющая последовательность чисел Фибоначчи:

function fibonacci(n) {
  if (n === 0 || n === 1)
    return n;
  else
    return fibonacci(n - 1) + fibonacci(n - 2);
}

Для больших чисел n количество вызовов функции растёт очень быстро. Уже для n=50 это порядка 40 миллиардов вызовов.

Используя идею мемоизации, то есть кеширования промежуточного результата, можно добиться уменьшения количества вызовов для n=50 до всего лишь 99:

var fibonacci = (function() {
  var memo = {};

  function f(n) {
    var value;

    if (n in memo) {
      value = memo[n];
    } else {
      if (n === 0 || n === 1)
        value = n;
      else
        value = f(n - 1) + f(n - 2);

      memo[n] = value;
    }

    return value;
  }

  return f;
})();

Если функция имеет дело с несколькими аргументами, то нужно хранить в кеше их все. Вместо того,  чтобы каждый раз писать «мемоизированную» версию функции, можно использовать функцию-обёртку вроде такой:

function memoized (fn, keymaker) {
   var lookupTable = {},
   key;
   keymaker || (keymaker = function (args) {
      return JSON.stringify(args)
   });
   return function () {
      var key = keymaker.call(this, arguments);
      return lookupTable[key] || (
         lookupTable[key] = fn.apply(this, arguments)
      )
   }
}

Используется она очень просто:

var memoizedFibonacci = memoized( function (n) {
  if (n === 0 || n === 1)
    return n;
  else
    return memoizedFibonacci (n - 1) + memoizedFibonacci (n - 2);
});

memoizedFibonacci (50);

Мемоизация полезна, когда вы передаёте в функцию заранее известный набор аргументов и когда результат функции будет всегда одинаковым при одинаковых аргументах. Если же функция не даёт одинакового результата при тех же аргументах, то мемоизация будет бесполезна.

Код большинства примеров взят из статьи   Implementing Memoization in Javascript