typing and refactoring on the way
diff --git a/wally/config.py b/wally/config.py
index c5d1db0..59db0e1 100644
--- a/wally/config.py
+++ b/wally/config.py
@@ -1,141 +1,60 @@
-import os
-import uuid
-import functools
-
-import yaml
-
-try:
-    from petname import Generate as pet_generate
-except ImportError:
-    def pet_generate(x, y):
-        return str(uuid.uuid4())
-
-from . import pretty_yaml
-
+from typing import Any, Dict
+from .storage import IStorable, IStorage
 
 class NoData:
     @classmethod
-    def get(cls, name, x):
+    def get(cls: type, name: str, x: Any) -> type:
         return cls
 
 
-class Config:
-    def __init__(self, val=None):
-        if val is not None:
-            self.update(val)
-        self.results_dir = None
-        self.run_uuid = None
-        self.settings = {}
-        self.run_params_file = None
-        self.default_test_local_folder = None
-        self.hwinfo_directory = None
-        self.hwreport_fname = None
+class Config(IStorable):
+    # for mypy only
+    run_uuid = None  # type: str
+    storage_url = None  # type: str
+    comment = None  # type: str
+    keep_vm = None  # type: bool
+    no_tests = None  # type: bool
+    dont_discover_nodes = None  # type: bool
+    build_id = None  # type: str
+    build_description = None  # type: str
+    build_type = None  # type: str
 
-    def get(self, name, defval=None):
-        obj = self.__dict__
-        for cname in name.split("."):
-            obj = obj.get(cname, NoData)
+    def __init__(self, dct: Dict[str, Any]) -> None:
+        self.__dict__['_dct'] = dct
 
-        if obj is NoData:
-            return defval
-        return obj
+    def get(self, path: str, default: Any = NoData) -> Any:
+        curr = self
 
-    def update(self, val):
-        self.__dict__.update(val)
+        while path:
+            if '/' in path:
+                name, path = path.split('/', 1)
+            else:
+                name = path
+                path = ""
+
+            try:
+                curr = getattr(curr, name)
+            except AttributeError:
+                return default
+
+        return curr
+
+    def __getattr__(self, name: str) -> Any:
+        try:
+            val = self.__dct[name]
+        except KeyError:
+            raise AttributeError(name)
+
+        if isinstance(val, dict):
+            val = self.__class__(val)
+
+        return val
+
+    def __setattr__(self, name: str, val: Any):
+        self.__dct[name] = val
 
 
-def get_test_files(results_dir):
-    in_var_dir = functools.partial(os.path.join, results_dir)
-
-    res = dict(
-        run_params_file='run_params.yaml',
-        saved_config_file='config.yaml',
-        vm_ids_fname='os_vm_ids',
-        html_report_file='{0}_report.html',
-        load_report_file='load_report.html',
-        text_report_file='report.txt',
-        log_file='log.txt',
-        sensor_storage='sensor_storage',
-        nodes_report_file='nodes.yaml',
-        results_storage='results',
-        hwinfo_directory='hwinfo',
-        hwreport_fname='hwinfo.txt',
-        raw_results='raw_results.yaml')
-
-    res = dict((k, in_var_dir(v)) for k, v in res.items())
-    res['results_dir'] = results_dir
-    return res
-
-
-def load_config(file_name):
-    file_name = os.path.abspath(file_name)
-
-    defaults = dict(
-        testnode_log_root='/tmp/wally',
-        settings={}
-    )
-
-    raw_cfg = yaml.load(open(file_name).read())
-    raw_cfg['config_folder'] = os.path.dirname(file_name)
-    if 'include' in raw_cfg:
-        default_path = os.path.join(raw_cfg['config_folder'],
-                                    raw_cfg.pop('include'))
-        default_cfg = yaml.load(open(default_path).read())
-
-        # TODO: Need more intelectual configs merge?
-        default_cfg.update(raw_cfg)
-        raw_cfg = default_cfg
-
-    cfg = Config(defaults)
-    cfg.update(raw_cfg)
-
-    results_storage = cfg.settings.get('results_storage', '/tmp')
-    results_storage = os.path.abspath(results_storage)
-
-    existing = file_name.startswith(results_storage)
-
-    if existing:
-        cfg.results_dir = os.path.dirname(file_name)
-        cfg.run_uuid = os.path.basename(cfg.results_dir)
-    else:
-        # genarate result folder name
-        for i in range(10):
-            cfg.run_uuid = pet_generate(2, "_")
-            cfg.results_dir = os.path.join(results_storage,
-                                           cfg.run_uuid)
-            if not os.path.exists(cfg.results_dir):
-                break
-        else:
-            cfg.run_uuid = str(uuid.uuid4())
-            cfg.results_dir = os.path.join(results_storage,
-                                           cfg.run_uuid)
-
-    # setup all files paths
-    cfg.update(get_test_files(cfg.results_dir))
-
-    if existing:
-        cfg.update(load_run_params(cfg.run_params_file))
-
-    testnode_log_root = cfg.get('testnode_log_root')
-    testnode_log_dir = os.path.join(testnode_log_root, "{0}/{{name}}")
-    cfg.default_test_local_folder = testnode_log_dir.format(cfg.run_uuid)
-
-    return cfg
-
-
-def save_run_params(cfg):
-    params = {
-        'comment': cfg.comment,
-        'run_uuid': cfg.run_uuid
-    }
-
-    with open(cfg.run_params_file, 'w') as fd:
-        fd.write(pretty_yaml.dumps(params))
-
-
-def load_run_params(run_params_file):
-    with open(run_params_file) as fd:
-        dt = yaml.load(fd)
-
-    return dict(run_uuid=dt['run_uuid'],
-                comment=dt.get('comment'))
+class Context:
+    def __init__(self, config: Config, storage: IStorage):
+        self.config = config
+        self.storage = storage
\ No newline at end of file