08 May 2015

Job Interview Mistakes

This post is not about mistakes that you shouldn't do on interview, this post is about my own experience and mistakes that I already did. I'll concentrate only on technical ones, because these issues are the ones that you feel like something that could be easily solved or could be just fixed if you will explain them better to the interviewer. And this post will be updated, I hope I'll fail more, but not a lot to get frustrated :)

Oh, and I decided to do this post as a list of advices. I want it to be a list of DOs instead of DON'Ts


1. Don't allow yourself think that you are limited with time
Probably the interview will be booked in some calendar application, and you will know what is the time limit, also the interviewer could tell you that you (or he) have time limit. Don't allow yourself to think about time, just forget that it exists. You could loose a lot if you'll try to remember about it: you could propose worse solution, because you understand that it's faster to implement, or you can choose  data structure for one of the questions, and for the second one you'll keep it (though it's not suitable), because you remember about time.
Remember interviewer doesn't know why you choose worse solutions, he only sees that they are really bad.

2. You have a right to change architecture if during implementing you understood that it has flaws
This is somewhat related to the previous problem, you could keep an old architecture, which was your first idea, or you could change it right now and just don't finish because of the lack of time. Try to consult with the interviewer what he prefers: bad but implemented with explaining a better way or the half-implemented better solution. Sometimes interviewers prefer the first one, sometimes the second. And you'll never know this without asking.

3. Know one language that is suitable for all kind of questions
Know this one, or at least practice in your language of choice to do general programming tasks like the ones that you can find on hackerrank.com.
In my situation there was a mistake that I used Erlang on daily basis and used Common Lisp for solving some of the programming tasks, and unfortunately I didn't solve them constantly - only from time to time. And when I was asked to do task related to graphs I was a bit confused, because I had to think not only about the task, but about the language syntax as well. And it makes a bad impression, interviewer doesn't know why you are so slow and confused.

4. Don't use Common Lisp during interview process (or other rare language)
This is my favorite mistake. If I'll be doing it in another interview, just show me this text again :)
Common Lisp is great language, it has so much abilities and it could be used in so many ways. You probably think that if you will show the interviewer CL, he will be at least ok with seeing it. But the truth is sad: the number of the people who doesn't understand what CL is, is about 100%. Most of them believe that it's a functional language, so when you'll be using classical CL programming patterns, don't be surprised when the interviewer will admit to himself "He clearly knows functional programming and is comfortable with it, yet I didn't like the way it was applied during the interview".

PS:
Remember, interviewing process is held not on your field and you can't apply here your rules. It's a game with the rules created by interviewer. And it's not a court, you don't have any chance to protest against the decision.

29 May 2011

Examples on how to use cl-odesk

First of all you need to get keys to use oDesk API.

Let's load cl-odesk. There are 2 ways: to use quicklisp (as of now, 29 May 2011, quicklisp version of cl-odesk has no all the features) or to do it by hand.
Quicklisp way:
(ql:quickload 'odesk)

By hand: fetch latest version from github. Than run at your repl:
(load "odesk.asd")
(require :odesk)


Now let's do some queries to odesk. First we need to define connection. You will need PUBLIC_KEY, PRIVATE_KEY and TOKEN. The last one you can get only by authenticating yourself in your favourite web browser. You can check the logic of this at restas-odesk. Pleas see routes.lisp file.

Let's imagine you already have that token.
We can create connection by instantiating API class:

(defparameter *test-connection*
(make-instance 'odesk:api-json
:public-key "PUBLIC"
:secret-key "SECRET"
:api-token "TOKEN"))


Here is macro that can ease your life a lot:

(with-odesk (:connection con
:public-key "PUBLIC"
:secret-key "SECRET"
:api-token "TOKEN")
(print con))


And another macro that can help too:

(connect-odesk (:public-key "PUBLIC"
:secret-key "SECRET"
:api-token "TOKEN"))


Now let's do request to get info about user.
1) If we go first way and created variable *test-connection*

CL-USER> (odesk:hr/get-user :connection *test-connection*)
("{\"server_time\":\"1306690187\",\"auth_user\":{\"first_name\":\"Dmitriy\",
\"last_name\":\"Budashny\",\"uid\":\"dbudashny\",\"mail\":\"dbudashny@odesk.com\",
\"messenger_id\":\"\",\"messenger_type\":\"\",\"timezone\":\"EET\",
\"timezone_offset\":\"10800\"},\"user\":{\"timezone\":\"UTC+02:00 Eastern Europe\",
\"status\":\"active\",\"timezone_offset\":\"10800\",
\"public_url\":\"https:\\/\\/www.odesk.com\\/users\\/~~d6114868dcf921c5\",
\"last_name\":\"Budashny\",\"email\":\"dbudashny@odesk.com\",\"reference\":\"1001150\",
\"id\":\"dbudashny\",\"is_provider\":\"1\",\"first_name\":\"Dmitriy\"}}")

2) If we go the second way and will use with-odesk macro.
a) subvariant with defining connection explicitly:

CL-USER> (odesk:with-odesk
(:connection my-con
:public-key "PUBLIC"
:secret-key "SECRET"
:api-token "TOKEN")
(odesk:hr/get-user :connection my-con))
("{\"server_time\":\"1306690187\",\"auth_user\":{\"first_name\":\"Dmitriy\",
\"last_name\":\"Budashny\",\"uid\":\"dbudashny\",\"mail\":\"dbudashny@odesk.com\",
\"messenger_id\":\"\",\"messenger_type\":\"\",\"timezone\":\"EET\",
\"timezone_offset\":\"10800\"},\"user\":{\"timezone\":\"UTC+02:00 Eastern Europe\",
\"status\":\"active\",\"timezone_offset\":\"10800\",
\"public_url\":\"https:\\/\\/www.odesk.com\\/users\\/~~d6114868dcf921c5\",
\"last_name\":\"Budashny\",\"email\":\"dbudashny@odesk.com\",\"reference\":\"1001150\",
\"id\":\"dbudashny\",\"is_provider\":\"1\",\"first_name\":\"Dmitriy\"}}")

b) subvariant with default connection key:

CL-USER> (odesk:with-odesk
(:public-key "PUBLIC"
:secret-key "SECRET"
:api-token "TOKEN")
(odesk:hr/get-user))
("{\"server_time\":\"1306690187\",\"auth_user\":{\"first_name\":\"Dmitriy\",
\"last_name\":\"Budashny\",\"uid\":\"dbudashny\",\"mail\":\"dbudashny@odesk.com\",
\"messenger_id\":\"\",\"messenger_type\":\"\",\"timezone\":\"EET\",
\"timezone_offset\":\"10800\"},\"user\":{\"timezone\":\"UTC+02:00 Eastern Europe\",
\"status\":\"active\",\"timezone_offset\":\"10800\",
\"public_url\":\"https:\\/\\/www.odesk.com\\/users\\/~~d6114868dcf921c5\",
\"last_name\":\"Budashny\",\"email\":\"dbudashny@odesk.com\",\"reference\":\"1001150\",
\"id\":\"dbudashny\",\"is_provider\":\"1\",\"first_name\":\"Dmitriy\"}}")


3) Third way is for those who want to create connection globally and then use it in the code with-out the need to use with-odesk macro:

CL-USER> (odesk:connect-odesk (:public-key "PUBLIC"
:secret-key "SECRET"
:api-token "TOKEN"))
#<ODESK:API-JSON {CB4EF11}>
CL-USER> (odesk:hr/get-user)
("{\"server_time\":\"1306690187\",\"auth_user\":{\"first_name\":\"Dmitriy\",
\"last_name\":\"Budashny\",\"uid\":\"dbudashny\",\"mail\":\"dbudashny@odesk.com\",
\"messenger_id\":\"\",\"messenger_type\":\"\",\"timezone\":\"EET\",
\"timezone_offset\":\"10800\"},\"user\":{\"timezone\":\"UTC+02:00 Eastern Europe\",
\"status\":\"active\",\"timezone_offset\":\"10800\",
\"public_url\":\"https:\\/\\/www.odesk.com\\/users\\/~~d6114868dcf921c5\",
\"last_name\":\"Budashny\",\"email\":\"dbudashny@odesk.com\",\"reference\":\"1001150\",
\"id\":\"dbudashny\",\"is_provider\":\"1\",\"first_name\":\"Dmitriy\"}}")

23 May 2011

Django Offline Messages on PyPI

Finally decided to add Django Offline Messages to PyPI. Was very wondered that it could be done so easy, just type

python setup.py register



And got the result in some seconds:
running register
warning: register: missing required meta-data: url
Registering django-offline-messages to http://pypi.python.org/pypi
Server response (200): OK

05 April 2011

Common Lisp bindings for oDesk API

Today I've released cl-odesk 0.1.0 and few days ago was also released restas-odesk 0.1.0.



UPD: You can find examples here.

07 February 2011

Django Offline Messages

There was a way in Django to leave a message in User.message_set, so the user will be able to see this message after login. But this storage is deprecated as of now and will be totally removed in Django 1.4. That forced me to create database storage for messages. Here it is: django-offline-messages.

To use it you have to add some options to your settings.py file:

  • Add 'offline_messages' to INSTALLED_APPS

  • Set MESSAGE_STORAGE to 'offline_messages.storage.OfflineStorageEngine'



If you want to create a message, just type:

from offline_messages.utils import create_offline_message

user = User.objects.get(username='dbudashny')
create_offline_message(user, "This is a message")

25 October 2010

PyCon Ukraine. How Emacs-user can hack oDesk and get a job :)


(defmacro hack-odesk ()
'(http-post "http://spreadsheets.google.com/formResponse?formkey=dGVtN19mWlpLUDA2THJVU1U5a1h4NlE6MQ&ifq"
(list (cons "entry.3.group" "Emacs")
(cons "entry.4.group" "Emacs")
(cons "entry.5.group" "Emacs")
(cons "entry.6.group" "Emacs")
(cons "entry.7.group" "Emacs")
(cons "entry.8.group" "Emacs")
(cons "entry.9.group" "Emacs")
(cons "entry.10.single" (read-from-minibuffer "Enter how we can contact you: "))
(cons "pageNumber" "0")
(cons "backupCache" "")
(cons "submit" "True"))
'utf-8
'(("User-Agent" . "Mozilla/5.0 (X11; U; Linux i686; uk; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10."))))

26 October 2009

Quick Guide to SNMP and Mnesia

There is a good documentation on SNMP, Mnesia and MIB Writing, but it's impossible to find any good document that will guide you step-by-step to understanding howto create SNMP System which you can fill from Mnesia. So let's start ...

Imagine, you need to write database for some company, and one of the tables, let's name it empTable (keep in mind that name of the table in Mnesia and name of the table in MIB-file must be the same) contains such attributes: Id, Name, Phone Number.

First, we are going to write small MIB file w/ name EmpMIB.mib:



EmpMIB DEFINITIONS ::= BEGIN

IMPORTS
DisplayString, RowStatus FROM SNMPv2-TC
OBJECT-GROUP FROM SNMPv2-CONF
OBJECT-TYPE, MODULE-IDENTITY, enterprises FROM SNMPv2-SMI;

empMib MODULE-IDENTITY
LAST-UPDATED "200910261250"
ORGANIZATION "Riot"
CONTACT-INFO "E-mail: dmitriy.budashny@gmail.com
Dmitriy Budashny"
DESCRIPTION
"Module for employees"
::= { enterprises 66666 }


emp OBJECT IDENTIFIER ::= { empMib 5 }

empTable OBJECT-TYPE
SYNTAX SEQUENCE OF EmpEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"A table with information about employees."
::= { emp 1}

empEntry OBJECT-TYPE
SYNTAX EmpEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
""
INDEX { empDepNo, empName }
::= { empTable 1 }

EmpEntry ::=
SEQUENCE {
empDepNo INTEGER,
empName DisplayString,
empTelNo DisplayString,
empStatus RowStatus
}

empDepNo OBJECT-TYPE
SYNTAX INTEGER ( 1..65535 )
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"Number of department"
::= { empEntry 1 }

empName OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"The name of the employee"
::= { empEntry 2 }

empTelNo OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"The phone number"
::= { empEntry 3 }

empStatus OBJECT-TYPE
SYNTAX RowStatus
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"Status ?!"
::= { empEntry 4 }

empGroups OBJECT IDENTIFIER ::= { empMib 6 }

empGroup OBJECT-GROUP
OBJECTS { empDepNo, empName, empTelNo, empStatus }
STATUS current
DESCRIPTION
"A collection of objects providing employee information"
::= { empGroups 1 }


END


Also we need company.erl file:



-module(company).

-export([init/0, insert_record/1]).

init() ->
mnesia:create_table([{name, empTable},
{snmp, [{key, {integer, string}}]},
{attributes, [key, telno, row_status]}]).

insert_record(Record) ->
Fun = fun() ->
mnesia:write(Record)
end,
mnesia:transaction(Fun).

Then we will create config files for snmp agent and snmp manager:


snmp/agent/conf/agent.conf:

{intAgentIpAddress, [127,0,0,1]}.
{intAgentUDPPort, 4000}.
{snmpEngineID, "agent's engine"}.
{snmpEngineMaxMessageSize, 484}.

snmp/agent/conf/community.conf:

{"public", "public", "initial", "", ""}.

snmp/agent/conf/standard.conf:

{sysName, "SNMP Quick Start HowTo Demo"}.
{sysDescr, "Erlang/OTP Agent"}.
{sysContact, "vances@motivity.ca"}.
{sysLocation, "5th Floor machine room, rack 21A"}.
{sysObjectID, [3,6,1,4,1,193,19]}. % {ericsson otp}
{sysServices, 72}.
{snmpEnableAuthenTraps, enabled}.

snmp/agent/conf/vacm.conf:

{vacmViewTreeFamily, "restricted", [1,3,6,1], included, null}.%% vacmViewTreeFamilyTable in the SNMP-VIEW-BASED-ACM-MIB.
{vacmSecurityToGroup, v2c, "initial", "initial"}.
{vacmSecurityToGroup, usm, "initial", "initial"}.
{vacmAccess, "initial", "", any, noAuthNoPriv, exact, "restricted", "", "restricted"}.
{vacmAccess, "initial", "", usm, authNoPriv, exact, "internet", "internet", "internet"}.
{vacmAccess, "initial", "", usm, authPriv, exact, "internet", "internet", "internet"}.
{vacmViewTreeFamily, "internet", [1,3,6,1], included, null}.
{vacmViewTreeFamily, "restricted", [1,3,6,1], included, null}.

snmp/manager/conf/agents.conf:

{"simple_user", "otp agent", "public", [127,0,0,1], 4000, "agent's engine",
infinity, 484, v2, v2c, "initial", noAuthNoPriv}.

snmp/manager/conf/manager.conf:

{port, 5000}.
{address, [127,0,0,1]}.
{engine_id, "manager's engine"}.
{max_message_size, 484}.

snmp/manager/conf/users.conf:

{"simple_user", snmpm_user_default, undefined}.

And now the real fun begins:


dym@enfer:~/tmp/proga/erlang/mnesia_snmp$ mkdir EmpDB
dym@enfer:~/tmp/proga/erlang/mnesia_snmp$ erl -sname ms@enfer -mnesia dir '"./EmpDB"' -config snmp/
Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.3 (abort with ^G)
(ms@enfer)1> mnesia:create_schema([node()]).
ok
(ms@enfer)2> mnesia:start().
ok
(ms@enfer)3> c(company).
{ok,company}
(ms@enfer)4> company:init().
{atomic,ok}
(ms@enfer)5> application:start(snmp).

=ERROR REPORT==== 26-Oct-2009::15:46:52 ===
** Configuration error: [FRAMEWORK-MIB]: missing context.conf file => generating a default file

=INFO REPORT==== 26-Oct-2009::15:46:52 ===
[ snmp : agent : snmp_user_based_sm_mib : <0.95.0> ]
USM: Incomplete configuration. Generating empty usm.conf.
ok
(ms@enfer)6> application:which_applications().
[{snmp,"SNMP CXC 138 13","4.13.5"},
{mnesia,"MNESIA CXC 138 12","4.4.11"},
{stdlib,"ERTS CXC 138 10","1.16.3"},
{kernel,"ERTS CXC 138 10","2.13.3"}]

So you see, applications mnesia and snmp are running


(ms@enfer)7> snmpc:compile("EmpMIB", [{db, mnesia}]).
{ok,"./EmpMIB.bin"}
(ms@enfer)8> snmpa:load_mibs(["EmpMIB"]).
ok

As of now our table is empty, but we are going to change this:


(ms@enfer)9> company:insert_record({empTable, {1,"Dmitriy Budashny"}, "1201", 1}).
{atomic,ok}

Let's open another console:


dym@enfer:~$ snmpwalk -c public -v 2c localhost:4000 .1.3.6.1.4.1.66666
SNMPv2-SMI::enterprises.66666.5.1.1.1.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = INTEGER: 1
SNMPv2-SMI::enterprises.66666.5.1.1.2.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = STRING: "Dmitriy Budashny"
SNMPv2-SMI::enterprises.66666.5.1.1.3.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = STRING: "1201"
SNMPv2-SMI::enterprises.66666.5.1.1.4.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = INTEGER: 1

And then we'll add another guy with phone number 1305:


(ms@enfer)10> company:insert_record({empTable, {2,"Andrew Sidlyarenko"}, "1305", 1}).
{atomic,ok}

Run snmpwalk again:


dym@enfer:~$ snmpwalk -c public -v 2c localhost:4000 .1.3.6.1.4.1.66666
SNMPv2-SMI::enterprises.66666.5.1.1.1.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = INTEGER: 1
SNMPv2-SMI::enterprises.66666.5.1.1.1.2.18.65.110.100.114.101.119.32.83.105.100.108.121.97.114.101.110.107.111 = INTEGER: 2
SNMPv2-SMI::enterprises.66666.5.1.1.2.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = STRING: "Dmitriy Budashny"
SNMPv2-SMI::enterprises.66666.5.1.1.2.2.18.65.110.100.114.101.119.32.83.105.100.108.121.97.114.101.110.107.111 = STRING: "Andrew Sidlyarenko"
SNMPv2-SMI::enterprises.66666.5.1.1.3.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = STRING: "1201"
SNMPv2-SMI::enterprises.66666.5.1.1.3.2.18.65.110.100.114.101.119.32.83.105.100.108.121.97.114.101.110.107.111 = STRING: "1305"
SNMPv2-SMI::enterprises.66666.5.1.1.4.1.16.68.109.105.116.114.105.121.32.66.117.100.97.115.104.110.121 = INTEGER: 1
SNMPv2-SMI::enterprises.66666.5.1.1.4.2.18.65.110.100.114.101.119.32.83.105.100.108.121.97.114.101.110.107.111 = INTEGER: 1

PS: It's not complete guide about Mnesia or SNMP or MIBs. If you want more, I can recommend you some books/articles/sites:


Total Pageviews

Followers