SQL, ఏది సరళమైనది? మనలో ప్రతి ఒక్కరూ ఒక సాధారణ అభ్యర్థనను వ్రాయవచ్చు - మేము టైప్ చేస్తాము ఎంచుకోండి, అవసరమైన నిలువు వరుసలను జాబితా చేయండి నుండి, పట్టిక పేరు, కొన్ని షరతులు (ఇక్కడ మరియు అంతే - ఉపయోగకరమైన డేటా మన జేబులో ఉంది మరియు (దాదాపు) ఆ సమయంలో ఏ DBMS హుడ్ కింద ఉందో దానితో సంబంధం లేకుండా (లేదా ఉండవచ్చు
మరియు వెంటనే ప్రారంభిద్దాం
ఆబ్జెక్ట్-రిలేషనల్ మ్యాపింగ్
ORM మద్దతుదారులు సాంప్రదాయకంగా వేగం మరియు అభివృద్ధి సౌలభ్యం, DBMS నుండి స్వాతంత్ర్యం మరియు క్లీన్ కోడ్కు విలువ ఇస్తారు. మనలో చాలా మందికి, డేటాబేస్తో పని చేసే కోడ్ (మరియు తరచుగా డేటాబేస్ కూడా)
ఇది సాధారణంగా ఇలా కనిపిస్తుంది ...
@Entity
@Table(name = "stock", catalog = "maindb", uniqueConstraints = {
@UniqueConstraint(columnNames = "STOCK_NAME"),
@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "STOCK_ID", unique = true, nullable = false)
public Integer getStockId() {
return this.stockId;
}
...
మోడల్ తెలివైన ఉల్లేఖనాలతో వేలాడదీయబడింది మరియు తెర వెనుక ఎక్కడో ఒక సాహసోపేతమైన ORM టన్నుల కొద్దీ SQL కోడ్ని ఉత్పత్తి చేస్తుంది మరియు అమలు చేస్తుంది. మార్గం ద్వారా, డెవలపర్లు తమ డేటాబేస్ నుండి కిలోమీటర్ల సారాంశాలతో తమను తాము వేరుచేయడానికి తమ వంతు ప్రయత్నం చేస్తున్నారు, ఇది కొన్నింటిని సూచిస్తుంది
బారికేడ్ల యొక్క మరొక వైపు, స్వచ్ఛమైన "చేతితో తయారు చేసిన" SQL యొక్క అనుచరులు అదనపు లేయర్లు మరియు సంగ్రహణలు లేకుండా వారి DBMS నుండి మొత్తం రసాన్ని పిండగల సామర్థ్యాన్ని గమనించారు. ఫలితంగా, “డేటా-సెంట్రిక్” ప్రాజెక్ట్లు కనిపిస్తాయి, ఇక్కడ ప్రత్యేకంగా శిక్షణ పొందిన వ్యక్తులు డేటాబేస్లో పాల్గొంటారు (వారు కూడా “ప్రాథమికవాదులు”, వారు కూడా “ప్రాథమికులు”, వారు కూడా “బాస్డెనర్లు” మొదలైనవి), మరియు డెవలపర్లు వివరాల్లోకి వెళ్లకుండా, రెడీమేడ్ వీక్షణలు మరియు నిల్వ చేసిన విధానాలను మాత్రమే "పుల్" చేయాలి.
మనం రెండు ప్రపంచాలలో అత్యుత్తమమైన వాటిని కలిగి ఉంటే? జీవితాన్ని ధృవీకరించే పేరుతో అద్భుతమైన సాధనంలో ఇది ఎలా జరుగుతుంది
క్లోజుర్ అనేది DSLలను రూపొందించడానికి ఒక చక్కని భాష, కానీ SQL కూడా ఒక చల్లని DSL, మరియు మాకు మరొకటి అవసరం లేదు. S-ఎక్స్ప్రెషన్లు చాలా బాగున్నాయి, కానీ అవి ఇక్కడ కొత్తవి ఏవీ జోడించవు. ఫలితంగా, మేము బ్రాకెట్ల కొరకు బ్రాకెట్లను పొందుతాము. అంగీకరించవద్దు? డేటాబేస్పై సంగ్రహణ లీక్ అవ్వడం ప్రారంభించిన క్షణం కోసం వేచి ఉండండి మరియు మీరు ఫంక్షన్తో పోరాడడం ప్రారంభించండి (ముడి-sql)
అయితే నేను ఏమి చేయాలి? SQLని సాధారణ SQLగా వదిలివేద్దాం - ప్రతి అభ్యర్థనకు ఒక ఫైల్:
-- name: users-by-country
select *
from users
where country_code = :country_code
... ఆపై ఈ ఫైల్ని చదవండి, దీన్ని సాధారణ క్లోజుర్ ఫంక్షన్గా మారుస్తుంది:
(defqueries "some/where/users_by_country.sql"
{:connection db-spec})
;;; A function with the name `users-by-country` has been created.
;;; Let's use it:
(users-by-country {:country_code "GB"})
;=> ({:name "Kris" :country_code "GB" ...} ...)
"SQL దానంతట అదే, క్లోజుర్ స్వయంగా" సూత్రానికి కట్టుబడి, మీరు పొందుతారు:
- వాక్యనిర్మాణ ఆశ్చర్యాలు లేవు. మీ డేటాబేస్ (ఏదైనా వంటిది) SQL ప్రమాణానికి 100% అనుగుణంగా లేదు - కానీ ఇది Yesqlకి పట్టింపు లేదు. మీరు SQL సమానమైన సింటాక్స్తో ఫంక్షన్ల కోసం వేటలో సమయాన్ని వృథా చేయరు. మీరు ఎప్పటికీ ఫంక్షన్కి తిరిగి రావలసిన అవసరం లేదు (రా-sql "కొన్ని('ఫంకీ'::SYNTAX)")).
- ఉత్తమ ఎడిటర్ మద్దతు. మీ ఎడిటర్కి ఇప్పటికే అద్భుతమైన SQL మద్దతు ఉంది. SQLని SQLగా సేవ్ చేయడం ద్వారా మీరు దాన్ని ఉపయోగించవచ్చు.
- జట్టు అనుకూలత. మీ క్లోజుర్ ప్రాజెక్ట్లో మీరు ఉపయోగించే SQLని మీ DBAలు చదవగలవు మరియు వ్రాయగలవు.
- సులభమైన పనితీరు ట్యూనింగ్. సమస్యాత్మక ప్రశ్న కోసం ప్రణాళికను రూపొందించాలా? మీ ప్రశ్న సాధారణ SQL అయినప్పుడు ఇది సమస్య కాదు.
- ప్రశ్నలను మళ్లీ ఉపయోగించడం. అదే SQL ఫైల్లను ఇతర ప్రాజెక్ట్లలోకి లాగండి మరియు వదలండి ఎందుకంటే ఇది కేవలం పాత SQL మాత్రమే - దీన్ని భాగస్వామ్యం చేయండి.
నా అభిప్రాయం ప్రకారం, ఆలోచన చాలా బాగుంది మరియు అదే సమయంలో చాలా సులభం, దీనికి ధన్యవాదాలు ప్రాజెక్ట్ చాలా మందిని పొందింది
IDE & DB నిర్వాహకులు
సాధారణ రోజువారీ పనితో ప్రారంభిద్దాం. తరచుగా మేము డేటాబేస్లో కొన్ని వస్తువులను శోధించవలసి ఉంటుంది, ఉదాహరణకు, స్కీమాలో ఒక పట్టికను కనుగొని, దాని నిర్మాణాన్ని అధ్యయనం చేయండి (ఏ కాలమ్లు, కీలు, సూచికలు, పరిమితులు మొదలైనవి ఉపయోగించబడతాయి). మరియు ఏదైనా గ్రాఫికల్ IDE లేదా కొద్దిగా DB-మేనేజర్ నుండి, మొదటగా, మేము ఖచ్చితంగా ఈ సామర్ధ్యాలను ఆశిస్తున్నాము. తద్వారా ఇది వేగంగా ఉంటుంది మరియు అవసరమైన సమాచారంతో విండో డ్రా అయ్యే వరకు మీరు అరగంట వేచి ఉండాల్సిన అవసరం లేదు (ముఖ్యంగా రిమోట్ డేటాబేస్కు నెమ్మదిగా కనెక్షన్తో), మరియు అదే సమయంలో, అందుకున్న సమాచారం తాజాగా మరియు సంబంధితంగా ఉంటుంది, మరియు కాష్ చేయబడిన జంక్ కాదు. అంతేకాకుండా, మరింత క్లిష్టమైన మరియు పెద్ద డేటాబేస్ మరియు వాటి సంఖ్య ఎక్కువ, దీన్ని చేయడం చాలా కష్టం.
కానీ సాధారణంగా నేను మౌస్ని దూరంగా విసిరివేసి కోడ్ను వ్రాస్తాను. "HR" స్కీమాలో ఏ పట్టికలు (మరియు ఏ లక్షణాలతో) ఉన్నాయో మీరు కనుగొనవలసి ఉందని అనుకుందాం. చాలా DBMSలలో, ఇన్ఫర్మేషన్_స్కీమా నుండి ఈ సాధారణ ప్రశ్నతో ఆశించిన ఫలితాన్ని సాధించవచ్చు:
select table_name
, ...
from information_schema.tables
where schema = 'HR'
డేటాబేస్ నుండి డేటాబేస్ వరకు, ప్రతి DBMS సామర్థ్యాలను బట్టి అటువంటి సూచన పట్టికల కంటెంట్లు మారుతూ ఉంటాయి. మరియు, ఉదాహరణకు, MySQL కోసం, అదే రిఫరెన్స్ పుస్తకం నుండి మీరు ఈ DBMSకి నిర్దిష్టమైన టేబుల్ పారామితులను పొందవచ్చు:
select table_name
, storage_engine -- Используемый "движок" ("MyISAM", "InnoDB" etc)
, row_format -- Формат строки ("Fixed", "Dynamic" etc)
, ...
from information_schema.tables
where schema = 'HR'
ఒరాకిల్కు సమాచారం_స్కీమా తెలియదు, కానీ అది కలిగి ఉంది
select table_name
, pct_free -- Минимум свободного места в блоке данных (%)
, pct_used -- Минимум используемого места в блоке данных (%)
, last_analyzed -- Дата последнего сбора статистики
, ...
from all_tables
where owner = 'HR'
ClickHouse మినహాయింపు కాదు:
select name
, engine -- Используемый "движок" ("MergeTree", "Dictionary" etc)
, ...
from system.tables
where database = 'HR'
కాసాండ్రాలో (టేబుల్లకు బదులుగా కాలమ్ఫ్యామిలీలు మరియు స్కీమాలకు బదులుగా కీస్పేస్లను కలిగి ఉంటుంది)లో ఇలాంటిదే ఏదైనా చేయవచ్చు:
select columnfamily_name
, compaction_strategy_class -- Стратегия сборки мусора
, gc_grace_seconds -- Время жизни мусора
, ...
from system.schema_columnfamilies
where keyspace_name = 'HR'
చాలా ఇతర డేటాబేస్ల కోసం, మీరు ఇలాంటి ప్రశ్నలతో కూడా రావచ్చు (మొంగో కూడా ఉంది
వాస్తవానికి, ఈ విధంగా మీరు పట్టికల గురించి మాత్రమే కాకుండా, సాధారణంగా ఏదైనా వస్తువు గురించి సమాచారాన్ని పొందవచ్చు. కాలానుగుణంగా, దయగల వ్యక్తులు వివిధ డేటాబేస్ల కోసం అలాంటి కోడ్ను షేర్ చేస్తారు, ఉదాహరణకు, హబ్రా కథనాల శ్రేణిలో “PostgreSQL డేటాబేస్లను డాక్యుమెంట్ చేయడానికి విధులు” (
ఫలితంగా, వస్తువులను నావిగేట్ చేయడం మరియు శోధించడం యొక్క ఈ పద్ధతి చాలా సరళమైనది, చాలా సమయాన్ని ఆదా చేస్తుంది మరియు ఇప్పుడు అవసరమైన రూపంలో సమాచారాన్ని పొందేందుకు మిమ్మల్ని అనుమతిస్తుంది (ఉదాహరణకు, పోస్ట్లో వివరించబడింది
వస్తువులతో కార్యకలాపాలు
మేము అవసరమైన వస్తువులను కనుగొని, అధ్యయనం చేసిన తర్వాత, వాటితో ఉపయోగకరమైనది చేయడానికి ఇది సమయం. సహజంగానే, కీబోర్డ్ నుండి మీ వేళ్లను తీయకుండా కూడా.
పట్టికను తొలగించడం దాదాపు అన్ని డేటాబేస్లలో ఒకే విధంగా కనిపిస్తుందనేది రహస్యం కాదు:
drop table hr.persons
కానీ పట్టిక సృష్టితో అది మరింత ఆసక్తికరంగా మారుతుంది. దాదాపు ఏదైనా DBMS (అనేక NoSQLతో సహా) ఒక రూపంలో లేదా మరొక రూపంలో “పట్టికను సృష్టించగలదు” మరియు దాని యొక్క ప్రధాన భాగం కూడా కొద్దిగా భిన్నంగా ఉంటుంది (పేరు, నిలువు వరుసల జాబితా, డేటా రకాలు), కానీ ఇతర వివరాలు నాటకీయంగా భిన్నంగా ఉంటాయి మరియు వాటిపై ఆధారపడి ఉంటాయి అంతర్గత పరికరం మరియు నిర్దిష్ట DBMS సామర్థ్యాలు. నాకు ఇష్టమైన ఉదాహరణ ఏమిటంటే, ఒరాకిల్ డాక్యుమెంటేషన్లో “టేబుల్ సృష్టించు” సింటాక్స్ కోసం “నేక్డ్” BNFలు మాత్రమే ఉన్నాయి.
అలాగే, అనేక DBMSలు ఇతర DBMSలలో అందుబాటులో లేని వాటి స్వంత నిర్దిష్ట రకాల వస్తువులను కలిగి ఉన్నాయి. అంతేకాకుండా, మేము డేటాబేస్ ఆబ్జెక్ట్లపై మాత్రమే కాకుండా, DBMS లోనే కార్యకలాపాలను నిర్వహించగలము, ఉదాహరణకు, ఒక ప్రక్రియను "చంపడం", కొంత మెమరీ ప్రాంతాన్ని ఖాళీ చేయడం, ట్రేసింగ్ను ప్రారంభించడం, "చదవడానికి మాత్రమే" మోడ్కు మారడం మరియు మరెన్నో.
ఇప్పుడు కొద్దిగా గీయండి
డేటాబేస్ వస్తువులతో రేఖాచిత్రాన్ని రూపొందించడం మరియు వాటి మధ్య ఉన్న వస్తువులు మరియు కనెక్షన్లను అందమైన చిత్రంలో చూడటం అత్యంత సాధారణ పనులలో ఒకటి. దాదాపు ఏదైనా గ్రాఫికల్ IDE, వ్యక్తిగత “కమాండ్ లైన్” యుటిలిటీలు, ప్రత్యేక గ్రాఫికల్ సాధనాలు మరియు మోడలర్లు దీన్ని చేయగలరు. వారు మీ కోసం "వారు చేయగలిగినంత ఉత్తమంగా" ఏదో గీస్తారు, కానీ మీరు కాన్ఫిగరేషన్ ఫైల్లోని కొన్ని పారామితుల సహాయంతో లేదా ఇంటర్ఫేస్లోని చెక్బాక్స్ల సహాయంతో మాత్రమే ఈ ప్రక్రియను కొద్దిగా ప్రభావితం చేయవచ్చు.
కానీ ఈ సమస్య చాలా సరళంగా, మరింత సరళంగా మరియు సొగసైనదిగా మరియు కోడ్ సహాయంతో పరిష్కరించబడుతుంది. ఏదైనా సంక్లిష్టత యొక్క రేఖాచిత్రాలను రూపొందించడానికి, మేము అనేక ప్రత్యేకమైన మార్కప్ భాషలను (DOT, GraphML మొదలైనవి) కలిగి ఉన్నాము మరియు వాటి కోసం అటువంటి సూచనలను చదవగల మరియు వాటిని వివిధ ఫార్మాట్లలో దృశ్యమానం చేయగల అప్లికేషన్ల (GraphViz, PlantUML, Mermaid) యొక్క మొత్తం స్కాటరింగ్. . సరే, వస్తువులు మరియు వాటి మధ్య కనెక్షన్ల గురించి సమాచారాన్ని ఎలా పొందాలో మాకు ఇప్పటికే తెలుసు.
PlantUML మరియు ఉపయోగించి ఇది ఎలా ఉంటుందో ఇక్కడ ఒక చిన్న ఉదాహరణ ఉంది
select '@startuml'||chr(10)||'hide methods'||chr(10)||'hide stereotypes' union all
select distinct ccu.table_name || ' --|> ' ||
tc.table_name as val
from table_constraints as tc
join key_column_usage as kcu
on tc.constraint_name = kcu.constraint_name
join constraint_column_usage as ccu
on ccu.constraint_name = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY'
and tc.table_name ~ '.*' union all
select '@enduml'
మరియు మీరు కొంచెం ప్రయత్నిస్తే, దాని ఆధారంగా
SQL ప్రశ్న కొంచెం క్లిష్టంగా ఉంటుంది
-- Шапка
select '@startuml
!define Table(name,desc) class name as "desc" << (T,#FFAAAA) >>
!define primary_key(x) <b>x</b>
!define unique(x) <color:green>x</color>
!define not_null(x) <u>x</u>
hide methods
hide stereotypes'
union all
-- Таблицы
select format('Table(%s, "%s n information about %s") {'||chr(10), table_name, table_name, table_name) ||
(select string_agg(column_name || ' ' || upper(udt_name), chr(10))
from information_schema.columns
where table_schema = 'public'
and table_name = t.table_name) || chr(10) || '}'
from information_schema.tables t
where table_schema = 'public'
union all
-- Связи между таблицами
select distinct ccu.table_name || ' "1" --> "0..N" ' || tc.table_name || format(' : "A %s may haven many %s"', ccu.table_name, tc.table_name)
from information_schema.table_constraints as tc
join information_schema.key_column_usage as kcu on tc.constraint_name = kcu.constraint_name
join information_schema.constraint_column_usage as ccu on ccu.constraint_name = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY'
and ccu.constraint_schema = 'public'
and tc.table_name ~ '.*'
union all
-- Подвал
select '@enduml'
మీరు దగ్గరగా చూస్తే, అనేక విజువలైజేషన్ సాధనాలు కూడా ఇలాంటి ప్రశ్నలను ఉపయోగిస్తాయి. నిజమే, ఈ అభ్యర్థనలు సాధారణంగా లోతుగా ఉంటాయి
కొలమానాలు మరియు పర్యవేక్షణ
సాంప్రదాయకంగా సంక్లిష్టమైన అంశానికి వెళ్దాం - డేటాబేస్ పనితీరు పర్యవేక్షణ. "నా స్నేహితులలో ఒకరు" నాకు చెప్పిన ఒక చిన్న నిజమైన కథ నాకు గుర్తుంది. మరొక ప్రాజెక్ట్లో ఒక నిర్దిష్ట శక్తివంతమైన DBA నివసించారు, మరియు కొంతమంది డెవలపర్లు అతనికి వ్యక్తిగతంగా తెలుసు, లేదా అతనిని వ్యక్తిగతంగా చూసారు (వాస్తవానికి, పుకార్ల ప్రకారం, అతను తదుపరి భవనంలో ఎక్కడో పనిచేసినప్పటికీ) . గంట “X” వద్ద, పెద్ద రిటైలర్ యొక్క పొడక్షన్ సిస్టమ్ మరోసారి “చెడుగా అనిపించడం” ప్రారంభించినప్పుడు, అతను ఒరాకిల్ ఎంటర్ప్రైజ్ మేనేజర్ నుండి గ్రాఫ్ల స్క్రీన్షాట్లను నిశ్శబ్దంగా పంపాడు, దానిపై అతను “గ్రహణశక్తి” కోసం ఎరుపు మార్కర్తో క్లిష్టమైన ప్రదేశాలను జాగ్రత్తగా హైలైట్ చేశాడు ( ఇది తేలికగా చెప్పాలంటే, పెద్దగా సహాయం చేయలేదు). మరియు ఈ "ఫోటో కార్డ్" ఆధారంగా నేను చికిత్స చేయవలసి వచ్చింది. అదే సమయంలో, విలువైన (పదం యొక్క రెండు భావాలలో) ఎంటర్ప్రైజ్ మేనేజర్కి ఎవరికీ ప్రాప్యత లేదు, ఎందుకంటే సిస్టమ్ సంక్లిష్టమైనది మరియు ఖరీదైనది, అకస్మాత్తుగా "డెవలపర్లు ఏదో ఒకదానిపై పొరపాట్లు చేస్తారు మరియు ప్రతిదీ విచ్ఛిన్నం చేస్తారు." అందువల్ల, డెవలపర్లు "అనుభవపూర్వకంగా" బ్రేక్ల స్థానాన్ని మరియు కారణాన్ని కనుగొన్నారు మరియు పాచ్ను విడుదల చేశారు. DBA నుండి బెదిరింపు లేఖ సమీప భవిష్యత్తులో మళ్లీ రాకపోతే, ప్రతి ఒక్కరూ ఊపిరి పీల్చుకుని తమ ప్రస్తుత పనులకు (కొత్త లేఖ వరకు) తిరిగి వస్తారు.
కానీ పర్యవేక్షణ ప్రక్రియ మరింత ఆహ్లాదకరంగా మరియు స్నేహపూర్వకంగా కనిపిస్తుంది మరియు ముఖ్యంగా అందరికీ అందుబాటులో మరియు పారదర్శకంగా ఉంటుంది. కనీసం దాని ప్రాథమిక భాగం, ప్రధాన పర్యవేక్షణ వ్యవస్థలకు అదనంగా (ఇవి ఖచ్చితంగా ఉపయోగకరంగా ఉంటాయి మరియు అనేక సందర్భాల్లో భర్తీ చేయలేనివి). ఏదైనా DBMS దాని ప్రస్తుత స్థితి మరియు పనితీరు గురించి సమాచారాన్ని పంచుకోవడానికి ఉచితంగా మరియు పూర్తిగా ఉచితం. అదే “బ్లడీ” ఒరాకిల్ DBలో, సిస్టమ్ వీక్షణల నుండి, ప్రక్రియలు మరియు సెషన్ల నుండి బఫర్ కాష్ స్థితి వరకు పనితీరు గురించి దాదాపు ఏదైనా సమాచారాన్ని పొందవచ్చు (ఉదాహరణకు,
ఈ విధంగా, కస్టమ్ sql ప్రశ్నలను నిర్వహించగల ఒకరకమైన మెట్రిక్స్ కలెక్టర్ (టెలిగ్రాఫ్, మెట్రిక్బీట్, కలెక్టెడ్)తో ఆయుధాలతో, ఈ మెట్రిక్ల నిల్వ (ఇన్ఫ్లక్స్డిబి, ఎలాస్టిక్సెర్చ్, టైమ్స్కేల్డ్బి) మరియు విజువలైజర్ (గ్రాఫానా, కిబానా), మీరు చాలా సులభంగా పొందవచ్చు. మరియు ఇతర సిస్టమ్-వైడ్ మెట్రిక్లతో (ఉదాహరణకు, అప్లికేషన్ సర్వర్ నుండి, OS నుండి, మొదలైన వాటి నుండి పొందబడింది) సన్నిహితంగా అనుసంధానించబడిన సౌకర్యవంతమైన పర్యవేక్షణ వ్యవస్థ. ఉదాహరణకు, ఇది pgwatch2లో చేయబడుతుంది, ఇది InfluxDB + Grafana కలయికను మరియు సిస్టమ్ వీక్షణల కోసం ప్రశ్నల సమితిని ఉపయోగిస్తుంది, వీటిని కూడా యాక్సెస్ చేయవచ్చు.
మొత్తం
మరియు ఇది సాధారణ SQL కోడ్ని ఉపయోగించి మా డేటాబేస్తో ఏమి చేయవచ్చో సుమారుగా జాబితా మాత్రమే. మీరు ఇంకా చాలా ఉపయోగాలు కనుగొనగలరని నేను ఖచ్చితంగా అనుకుంటున్నాను, వ్యాఖ్యలలో వ్రాయండి. మరియు మేము వీటన్నింటిని ఎలా ఆటోమేట్ చేయాలి మరియు తదుపరిసారి మీ CI/CD పైప్లైన్లో ఎలా చేర్చాలి (మరియు ముఖ్యంగా ఎందుకు) గురించి మాట్లాడుతాము.
మూలం: www.habr.com