refactoring and typing in progress
diff --git a/wally/storage.py b/wally/storage.py
index 5212f4a..02de173 100644
--- a/wally/storage.py
+++ b/wally/storage.py
@@ -2,8 +2,9 @@
 This module contains interfaces for storage classes
 """
 
+import os
 import abc
-from typing import Any, Iterable, TypeVar, Type, IO
+from typing import Any, Iterable, TypeVar, Type, IO, Tuple, Union, Dict, List
 
 
 class IStorable(metaclass=abc.ABCMeta):
@@ -32,46 +33,11 @@
 ObjClass = TypeVar('ObjClass')
 
 
-class IStorage(metaclass=abc.ABCMeta):
-    """interface for storage"""
-    @abc.abstractmethod
-    def __init__(self, path: str, existing_storage: bool = False) -> None:
-        pass
-
-    @abc.abstractmethod
-    def __setitem__(self, path: str, value: IStorable) -> None:
-        pass
-
-    @abc.abstractmethod
-    def __getitem__(self, path: str) -> IStorable:
-        pass
-
-    @abc.abstractmethod
-    def __contains__(self, path: str) -> bool:
-        pass
-
-    @abc.abstractmethod
-    def list(self, path: str) -> Iterable[str]:
-        pass
-
-    @abc.abstractmethod
-    def load(self, path: str, obj_class: Type[ObjClass]) -> ObjClass:
-        pass
-
-    @abc.abstractmethod
-    def get_stream(self, path: str) -> IO:
-        pass
-
-
 class ISimpleStorage(metaclass=abc.ABCMeta):
     """interface for low-level storage, which doesn't support serialization
     and can operate only on bytes"""
 
     @abc.abstractmethod
-    def __init__(self, path: str) -> None:
-        pass
-
-    @abc.abstractmethod
     def __setitem__(self, path: str, value: bytes) -> None:
         pass
 
@@ -103,13 +69,47 @@
         pass
 
 
-# TODO(koder): this is concrete storage and serializer classes to be implemented
-class FSStorage(IStorage):
+class FSStorage(ISimpleStorage):
     """Store all data in files on FS"""
 
+    def __init__(self, root_path: str, existing: bool) -> None:
+        self.root_path = root_path
+        if existing:
+            if not os.path.isdir(self.root_path):
+                raise ValueError("No storage found at {!r}".format(root_path))
+
+    def ensure_dir(self, path):
+        os.makedirs(path, exist_ok=True)
+
     @abc.abstractmethod
-    def __init__(self, root_path: str, serializer: ISerializer, existing: bool = False) -> None:
-        pass
+    def __setitem__(self, path: str, value: bytes) -> None:
+        path = os.path.join(self.root_path, path)
+        self.ensure_dir(os.path.dirname(path))
+        with open(path, "wb") as fd:
+            fd.write(value)
+
+    @abc.abstractmethod
+    def __getitem__(self, path: str) -> bytes:
+        path = os.path.join(self.root_path, path)
+        with open(path, "rb") as fd:
+            return fd.read()
+
+    @abc.abstractmethod
+    def __contains__(self, path: str) -> bool:
+        path = os.path.join(self.root_path, path)
+        return os.path.exists(path)
+
+    @abc.abstractmethod
+    def list(self, path: str) -> Iterable[Tuple[bool, str]]:
+        path = os.path.join(self.root_path, path)
+        for entry in os.scandir(path):
+            if not entry.name in ('..', '.'):
+                yield entry.is_file(), entry.name
+
+    @abc.abstractmethod
+    def get_stream(self, path: str, mode: str = "rb") -> IO:
+        path = os.path.join(self.root_path, path)
+        return open(path, mode)
 
 
 class YAMLSerializer(ISerializer):
@@ -117,6 +117,55 @@
     pass
 
 
-def make_storage(url: str, existing: bool = False) -> IStorage:
-    return FSStorage(url, YAMLSerializer(), existing)
+ISimpleStorable = Union[Dict, List, int, str, None, bool]
+
+
+class Storage:
+    """interface for storage"""
+    def __init__(self, storage: ISimpleStorage, serializer: ISerializer):
+        self.storage = storage
+        self.serializer = serializer
+
+    def __setitem__(self, path: str, value: IStorable) -> None:
+        self.storage[path] = self.serializer.pack(value)
+
+    @abc.abstractmethod
+    def __getitem__(self, path: str) -> ISimpleStorable:
+        return self.serializer.unpack(self.storage[path])
+
+    @abc.abstractmethod
+    def __contains__(self, path: str) -> bool:
+        return path in self.storage
+
+    @abc.abstractmethod
+    def list(self, path: str) -> Iterable[Tuple[bool, str]]:
+        return self.storage.list(path)
+
+    @abc.abstractmethod
+    def load(self, path: str, obj_class: Type[ObjClass]) -> ObjClass:
+        raw_val = self[path]
+        if obj_class in (int, str, dict, list, None):
+            if not isinstance(raw_val, obj_class):
+                raise ValueError("Can't load path {!r} into type {}. Real type is {}"
+                                 .format(path, obj_class, type(raw_val)))
+            return raw_val
+
+        if not isinstance(raw_val, dict):
+            raise ValueError("Can't load path {!r} into python type. Raw value not dict".format(path))
+
+        if not all(isinstance(str, key) for key in raw_val.keys):
+            raise ValueError("Can't load path {!r} into python type.".format(path) +
+                             "Raw not all keys in raw value is strings")
+
+        obj = ObjClass.__new__(ObjClass)
+        obj.__dict__.update(raw_val)
+        return obj
+
+    @abc.abstractmethod
+    def get_stream(self, path: str) -> IO:
+        return self.storage.get_stream(path)
+
+
+def make_storage(url: str, existing: bool = False) -> Storage:
+    return Storage(FSStorage(url, existing), YAMLSerializer())