Работа для программиста.

0

Самый изощренный способ найма на работу, с каким мне довелось столкнуться — найм программистов в украинские ИТ-компании.
Украина в настоящий момент, по некоторым оценкам, находится в числе лидеров в Европе по объему рынка ИТ-услуг. В основном — это аутсорс разработки ПО. По другим оценкам, в этом бизнесе задействовано около 100 тыс. человек. Рост рынка не остановился даже в 13-14 годах. Рынок остро нуждается в квалифицированных специалистах, с одной стороны, а с другой — испытывает наплыв неквалифицированной рабочей силы из депрессивных отраслей экономики.
Крупные компании содержат большой штат рекрутеров, которые активно ищут кандидатов на постоянно появляющиеся вакансии. Ищут активно и результативно. Первый контакт, обычно — с ними. После первого контакта, могут следовать несколько собеседований. Программист скорее всего попадет на техническое интервью, тест знания английского языка и интервью со специалистом по персоналу, которой должен понять уровень общей адекватности и способности к работе в коллективе. Иногда соискателю предлагаются тестовые задание различной сложности. В финале возможно собеседования с заказчиком.
Самое необычное впечатление, пожалуй, оставляет техническое интервью. Чтобы пройти его, обязательно нужно готовится. Весьма необычное ощущение, когда надо переключится из области решения задач в область фактических знаний(памяти). На интервью могут спросить сначала об глобальной концепции, типа наследования, а затем попросить на память перечислить методы какого-то класса. И такой режим беседы поддерживается на протяжении часа — полутора. Без подготовки, на основе только имеющегося опыта, не возможно ответить на все вопросы. А еще может оказаться, что интервьюер имеет свои, устоявшиеся взгляды, которые могут расходится с мнением разработчиков языка и тогда можно услышать что-то типа «Не знаю что там говорит Блох, но я считаю иначе!». Спорить категорически нельзя. Острые углы лучше обходить. Если интервьюер не считает, что overloading в Java является одним из видов полиморфизма, то настаивать на этом не стоит.
Общение с нетехническими специалистами — не такое стрессовое. Рекрутеры обычно очень вежливые и доброжелательные. Единственный нюанс — обратная связь: если в ходе собеседований, суммарно, на кандидата было выделено около трех часов, то экономить 10 минут на развернутое письмо по результатам собеседования — не логично, но это норма для некоторых рекрутеров, к сожалению. Разумеется, речь о ситуации, когда кандидатура по каким-то причинам не подошла.
<место для дополнений>
Мое видение ситуации очень субъективно. Возможно, в некоторых компания картина в корне отличается, что не делает её менее интересной. Мои выводы следующие:
1. Надо всегда быть в форме: постоянно учиться и пробовать что-то новое, даже если текущая работа не требует быть на острие технологий.
2. Важно уметь находить общий язык с любыми людьми. Иногда люди меняются. Иногда первое впечатление бывает обманчивым.
3. Композиция предпочтительнее наследования.

Беговой юбилей.

0

Финиш первого полумарафона.

Скоро год, как я добавил бег к своей физкультурной активности. С февраля 2016 все беговые занятия мною фиксируются в Strava, по данным которой, сегодня состоялась моя сотая пробежка. Юбилей! Одновременно, в ходе юбилейной пробежки, мой суммарный, зафиксированный Strava пробег, перевалил за тысячу километров. Юбилей! Этот пост — моя краткая беговая история. Она никому не будет полезна, у всех все индивидуально, поэтому опишу ее исключительно для себя, чтоб не забыть потом как все начиналось.

 

Исходные данные.

К моменту начала беговой активности, на протяжении десяти лет, я уже был активным физкультурником, но для бегуна я довольно массивный — больше 10 кг превышения пропорций обычного любителя бега на средние и длинные дистанции. Больше того, эта ситуация меня вполне устраивает, тонкие, как спички, руки, с острыми локтями, отсутствующие мышцы груди и торчащие из плеч кости — все это мне не нравится в конституции бегунов. У меня растет дочка, она считает отца образцом мужчины, образец должен быть сильным и смышленым, по-моему.

Старт.

Приняв решение начать бегать, глубокой осенью прошлого года я приобрел две пары беговых кроссовки(пульсомер у меня уже был), после этого обратной дороги не было. Собрав волю в карман, я поставил будильник на 6-00. Пробуждение было нелегким: темнота и холод на улице не способствовали легкому подъему, но я справился. Вышел на улицу и побежал.

Прогресс.

Опираясь на советы опытных бегунов и на прочитанные популярные статьи о беге, я методично прогрессировал. Как и многие, на волне энтузиазма, я не избежал травм, которые прерывали тренировочный процесс дважды на 2 недели и один раз на месяц с лишним. Беговые травмы были две, оба раза страдал голеностоп, не выдержавший скорость нарастания нагрузки. Предостережение первое: во время бега по короткому кругу школьного стадиона, одна нога нагружается сильно больше другой из-за постоянных виражей в одну строну, именно так я травмировал голеностоп первый раз. Предостережение второе: осенью и зимой утренние пробежки могут начинаться в темноте, что может привести к глупым травмам из-за незамеченной неровности, так я травмировал голеностоп второй раз. Третья травма была самой серьезной, но бегунам не свойственной, поэтому о ней писать не буду, отмечу лишь, что из-за нее, летом,  я практически начал бегать с самого начала.

Результаты.

Я начал с того, что за период с февраля по октябрь, пробежал больше 1000 км. за 100 пробежек, но это только данные Strava, до февраля я пользовался другими треккерами и пробежал незначительную дистанцию, которой можно пренебречь.
Так же я принял участие в нескольких соревнованиях, куда допускали любителей:
-Забег четыре сезона. Зима. Дистанция 10 км.,
-7-й Одесский Международный Марафон. Полумарафонская дистанция,
-Гонка Нации. Тилигул. Забег с препятствиями 5+км.
Соревнования — это особая тема, о которой можно много написать, может напишу позже, пока — только перечисление.

Очень важный для меня результат — за прошедший год я не пропустил ни одного рабочего дня по болезни! Из-за искривления секретной перегородки в носу, я подвержен простудным заболеваниям, за 42 года я не помню ни одно случая столь длительного безсопельного сезона.

Сейчас я готовлюсь к первому полному марафону, для этого использую программу подготовки от Asics. Если все будет гладко, то я пробегу 15 января полный марафон за 4 часа 1 минуту и 14 секунд. Жаль, что официального соревнования в этот день не нашлось, но для меня это не важно, то есть очень важно и очень жаль, но я справлюсь.

42.

Здесь хочу дописать немного на случай, если кто-то дочитает пост до конца и не найдет ответ на главный вопрос: зачем это все? Зачем тратить столько времени и сил на процесс, не имеющий никаких перспектив в плане спортивных достижений? Зачем издеваться над организмом, месяцами не видя результатов? И много других вопросов, связанных с более занимательными способами провести время. Это закономерные вопросы! Я долго не мог ответить на них. Все начиналось, как очередной каприз, каковым и оставалось благодаря упрямству до какого-то момента. Ясность ко мне пришла на финише моего первого полумарафона. С тех пор я всем отвечаю на подобные вопросы, не задумываясь: — Да, мне было очень физически приятно финишировать, но главное в том, что  моя шестилетняя дочь на финише, радуясь и обнимая меня, в восторге, назвала меня богатырем, а моя взрослая жена добавила, что я герой!  Это как-то высокопарно звучит, понимаю,  поэтому для богемных циников портосовщина: я бегаю потому что я бегаю.
Пока все.

17/10/16
Моя страва: https://www.strava.com/athletes/12582025/training/log

HTTPS Authentication with Spring Security.

0

Простой пример использования HTTPS аутентификации. Spring Security, Spring MVC, Spring Boot.

Традиционный Application.java.

package ua.com.computerman.hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) throws Throwable {
        SpringApplication.run(Application.class, args);
    }

}

Настройки embedded сервлет-контейнера EmbeddedServletContainerConfig.java.

package ua.com.computerman.hello;

import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.FileCopyUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

@Configuration
public class EmbeddedServletContainerConfig {
    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
        tomcat.addAdditionalTomcatConnectors(createSslConnector());
        return tomcat;
    }

    private Connector createSslConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
        try {
            File keystore = getKeyStoreFile();
            File truststore = keystore;
            connector.setScheme("https");
            connector.setSecure(true);
            connector.setPort(8443);
            protocol.setSSLEnabled(true);
            protocol.setKeystoreFile(keystore.getAbsolutePath());
            protocol.setKeystorePass("changeit");
            protocol.setTruststoreFile(truststore.getAbsolutePath());
            protocol.setTruststorePass("changeit");
            protocol.setKeyAlias("apitester");
            return connector;
        } catch (IOException ex) {
            throw new IllegalStateException(
                "cant access keystore: [" + "keystore" + "] or truststore: [" + "keystore" + "]",
                ex
            );
        }
    }

    private File getKeyStoreFile() throws IOException {
        ClassPathResource resource = new ClassPathResource("keystore");
        try {
            return resource.getFile();
        } catch (Exception ex) {
            File temp = File.createTempFile("keystore", ".tmp");
            FileCopyUtils.copy(resource.getInputStream(), new FileOutputStream(temp));
            return temp;
        }
    }
}

Незатейливая конфигурация Spring MVC.

package ua.com.computerman.hello;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
    
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/home").setViewName("home");
        registry.addViewController("/").setViewName("home");
        registry.addViewController("/hello").setViewName("hello");
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/ok").setViewName("ok");
    }

}

WebSecurityConfig.java.

package ua.com.computerman.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .requiresChannel()
            .antMatchers("/login").requiresSecure()
            .antMatchers("/**").requiresInsecure()
            .and()

            .authorizeRequests()
            .antMatchers("/", "/home").permitAll()
            .antMatchers("/**").fullyAuthenticated()
            .and()
            // Original: http://stackoverflow.com/q/28341645/285571
            .sessionManagement().sessionFixation().none()
            .and()

            .formLogin().loginPage("/login").permitAll().failureUrl("/login")
            .permitAll().and().logout().logoutUrl("/logout").permitAll().logoutSuccessUrl("/")
            .permitAll()
            // Disable CSRF for making /logout available for all HTTP methods (POST, GET...)
            .and().csrf().disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("user").password("user").roles("USER");
        auth
            .inMemoryAuthentication()
            .withUser("guest").password("guest").roles("USER");

    }
}

Шаблоны thymeleaf, подробнее о них тут.

hello.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Hello World!</title>
    </head>
    <body>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
        <p>Click <a th:href="@{/ok}">here</a> to visit the OK page.</p>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="Sign Out"/>
        </form>

    </body>
</html>

home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example</title>
    </head>
    <body>
        <h1>Welcome!</h1>
        
        <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
    </body>
</html>

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <title>Spring Security Example </title>
    </head>
    <body>
        <div th:if="${param.error}">
            Invalid username and password.
        </div>
        <div th:if="${param.logout}">
            You have been logged out.
        </div>
        <form th:action="@{/login}" method="post">
            <div><label> User Name : <input type="text" name="username"/> </label></div>
            <div><label> Password: <input type="password" name="password"/> </label></div>
            <div><input type="submit" value="Sign In"/></div>
        </form>
    </body>
</html>

ok.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Ok</title>
</head>
<body>
    <h1 th:inline="text">Ok [[${#httpServletRequest.remoteUser}]]!</h1>
    <p>Click <a th:href="@{/hello}">here</a> to back the hello page.</p>
    <form th:action="@{/logout}" method="post">
        <input type="submit" value="Sign Out"/>
    </form>

</body>
</html>

Код на GitHUB.

The simplest REST service.

0

Благодаря сочетанию Spring Boot и Spring MVC, простейший REST сервис можно сделать за пару минут, Для этого понадобится всего два класса по паре строк кода и минимальный pom.xml.

Простой контроллер AnswerController.java.

package ua.com.computerman.loony;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AnswerController {
    @RequestMapping("/")
    public String answer() {
        return "It works!";
    }
}

Главный класс приложения Application.java.

package ua.com.computerman.loony;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application extends SpringBootServletInitializer { 
    public static void main(String[] args) { 
        SpringApplication.run(Application.class, args); 
    } 
} 

Наследование от SpringBootServletInitializer не обязательно для запуска через Spring Boot, таким образом мы получаем возможность ручного развертывания .war файла на локальном сервлет-контейнере, если потребуется.

Незамысловатый pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ua.com.computerman</groupId>
    <artifactId>LoonyREST</artifactId>    
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

Примечательно, что для запуска приложения нет необходимости развертывать что-либо в сервлет-контейнер — Spring Boot использует по умолчанию embeded Tomcat 8.0.
После запуска появится возможность сразу обращаться к http://localhost:8080/ в браузере, в ответ вернется текст «It works!».

Код на GitHUB.

Заготовки для аутентификации.

0

1280px-SIGABA-patent

Постановка задачи.

Для реализации системы аутентификации пользователя необходимо подобрать реализации двух криптографических алгоритмов на Java и JavaScript:
алгоритм хеширования MD5(Message Digest 5);
симметричное блочное шифрование AES.

Continue reading

Перевод «JUnitBenchmarks: Tutorial».

0

timer

Оригинал: тут.

JUnitBenchmarks: Учебник.

Быстрый старт.
В овладении JUnitBenchmarks есть два ключевых элемента: аннотации и системные свойства, к счастью, большинство из них являются необязательными и требуются только для достижения специфических целей.

Превратите ваши JUnit4 тесты в тесты производительности.
Предполагается, что ваш класс уже является тестом Junit4. Например, предположим, что ваш тестовый класс выглядит следующим образом:

public class MyTest {
  @Test
  public void twentyMillis() throws Exception {
    Thread.sleep(20);
  }
}

Чтобы превратить этот тест в тест производительности, вам необходимо добавить правило для JUnit4 (rule), которое сообщит исполнителям тестов JUnit4 о необходимости прикрепить измерительный код к вашему тесту. Добавить такое правило легко, просто добавьте соответствующее поле, как в нижеследующем примере (строки с импортом опущены): Continue reading