diff --git a/examples/simple_fsm/src/main.rs b/examples/simple_fsm/src/main.rs
index 743f781a..3b7853c9 100644
--- a/examples/simple_fsm/src/main.rs
+++ b/examples/simple_fsm/src/main.rs
@@ -21,29 +21,12 @@ enum FavouriteMusic {
 
 impl FavouriteMusic {
     fn markup() -> ReplyKeyboardMarkup {
-        ReplyKeyboardMarkup {
-            keyboard: vec![vec![
-                KeyboardButton {
-                    text: "Rock".to_owned(),
-                    request: None,
-                },
-                KeyboardButton {
-                    text: "Metal".to_owned(),
-                    request: None,
-                },
-                KeyboardButton {
-                    text: "Pop".to_owned(),
-                    request: None,
-                },
-                KeyboardButton {
-                    text: "Other".to_owned(),
-                    request: None,
-                },
-            ]],
-            resize_keyboard: None,
-            one_time_keyboard: None,
-            selective: None,
-        }
+        ReplyKeyboardMarkup::default().append_row(vec![
+            KeyboardButton::new("Rock"),
+            KeyboardButton::new("Metal"),
+            KeyboardButton::new("Pop"),
+            KeyboardButton::new("Other"),
+        ])
     }
 }
 
@@ -70,21 +53,13 @@ impl Display for User {
     }
 }
 
-// ============================================================================
-// [Some macros]
-// ============================================================================
-
-#[macro_export]
-macro_rules! reply {
-    ($ctx:ident, $text:expr) => {
-        $ctx.reply($text).await?;
-    };
-}
-
 // ============================================================================
 // [Control our FSM]
 // ============================================================================
 
+type Ctx = SessionHandlerCtx<Message, User>;
+type Res = Result<SessionState<User>, RequestError>;
+
 async fn send_favourite_music_types(ctx: &Ctx) -> Result<(), RequestError> {
     ctx.bot
         .send_message(ctx.chat_id(), "Good. Now choose your favourite music:")
@@ -94,16 +69,14 @@ async fn send_favourite_music_types(ctx: &Ctx) -> Result<(), RequestError> {
     Ok(())
 }
 
-type Ctx = SessionHandlerCtx<Message, User>;
-type Res = Result<SessionState<User>, RequestError>;
-
 async fn start(ctx: Ctx) -> Res {
-    reply!(ctx, "Let's start! First, what's your full name?");
+    ctx.reply("Let's start! First, what's your full name?")
+        .await?;
     Ok(SessionState::Next(ctx.session))
 }
 
 async fn full_name(mut ctx: Ctx) -> Res {
-    reply!(ctx, "What a wonderful name! Your age?");
+    ctx.reply("What a wonderful name! Your age?").await?;
     ctx.session.full_name = Some(ctx.update.text().unwrap().to_owned());
     Ok(SessionState::Next(ctx.session))
 }
@@ -114,7 +87,7 @@ async fn age(mut ctx: Ctx) -> Res {
             send_favourite_music_types(&ctx).await?;
             ctx.session.age = Some(ok);
         }
-        Err(_) => reply!(ctx, "Oh, please, enter a number!"),
+        Err(_) => ctx.reply("Oh, please, enter a number!").await?,
     }
 
     Ok(SessionState::Next(ctx.session))
@@ -124,11 +97,11 @@ async fn favourite_music(mut ctx: Ctx) -> Res {
     match ctx.update.text().unwrap().parse() {
         Ok(ok) => {
             ctx.session.favourite_music = Some(ok);
-            reply!(ctx, format!("Fine. {}", ctx.session));
+            ctx.reply(format!("Fine. {}", ctx.session)).await?;
             Ok(SessionState::Exit)
         }
         Err(_) => {
-            reply!(ctx, "Oh, please, enter from the keyboard!");
+            ctx.reply("Oh, please, enter from the keyboard!").await?;
             Ok(SessionState::Next(ctx.session))
         }
     }
diff --git a/src/types/inline_keyboard_markup.rs b/src/types/inline_keyboard_markup.rs
index 0a35e799..8361509d 100644
--- a/src/types/inline_keyboard_markup.rs
+++ b/src/types/inline_keyboard_markup.rs
@@ -33,10 +33,6 @@ pub struct InlineKeyboardMarkup {
 /// let keyboard = InlineKeyboardMarkup::new().append_row(vec![url_button]);
 /// ```
 impl InlineKeyboardMarkup {
-    pub fn new() -> Self {
-        <_>::default()
-    }
-
     pub fn append_row(mut self, buttons: Vec<InlineKeyboardButton>) -> Self {
         self.inline_keyboard.push(buttons);
         self
diff --git a/src/types/keyboard_button.rs b/src/types/keyboard_button.rs
index 5e428201..ee68c4d1 100644
--- a/src/types/keyboard_button.rs
+++ b/src/types/keyboard_button.rs
@@ -24,6 +24,28 @@ pub struct KeyboardButton {
     pub request: Option<ButtonRequest>,
 }
 
+impl KeyboardButton {
+    /// Creates `KeyboardButton` with the provided `text` and all the other
+    /// fields set to `None`.
+    pub fn new<T>(text: T) -> Self
+    where
+        T: Into<String>,
+    {
+        Self {
+            text: text.into(),
+            request: None,
+        }
+    }
+
+    pub fn request<T>(mut self, val: T) -> Self
+    where
+        T: Into<Option<ButtonRequest>>,
+    {
+        self.request = val.into();
+        self
+    }
+}
+
 // Serialize + Deserialize are implemented by hand
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
 pub enum ButtonRequest {
diff --git a/src/types/reply_keyboard_markup.rs b/src/types/reply_keyboard_markup.rs
index f2cd674e..59707764 100644
--- a/src/types/reply_keyboard_markup.rs
+++ b/src/types/reply_keyboard_markup.rs
@@ -10,7 +10,7 @@ use crate::types::KeyboardButton;
 /// [custom keyboard]: https://core.telegram.org/bots#keyboards
 /// [Introduction to bots]: https://core.telegram.org/bots#keyboards
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Default)]
 pub struct ReplyKeyboardMarkup {
     /// Array of button rows, each represented by an Array of
     /// [`KeyboardButton`] objects
@@ -43,3 +43,46 @@ pub struct ReplyKeyboardMarkup {
     /// [`Message`]: crate::types::Message
     pub selective: Option<bool>,
 }
+
+impl ReplyKeyboardMarkup {
+    pub fn append_row(mut self, buttons: Vec<KeyboardButton>) -> Self {
+        self.keyboard.push(buttons);
+        self
+    }
+
+    pub fn append_to_row(
+        mut self,
+        button: KeyboardButton,
+        index: usize,
+    ) -> Self {
+        match self.keyboard.get_mut(index) {
+            Some(buttons) => buttons.push(button),
+            None => self.keyboard.push(vec![button]),
+        };
+        self
+    }
+
+    pub fn resize_keyboard<T>(mut self, val: T) -> Self
+    where
+        T: Into<Option<bool>>,
+    {
+        self.resize_keyboard = val.into();
+        self
+    }
+
+    pub fn one_time_keyboard<T>(mut self, val: T) -> Self
+    where
+        T: Into<Option<bool>>,
+    {
+        self.one_time_keyboard = val.into();
+        self
+    }
+
+    pub fn selective<T>(mut self, val: T) -> Self
+    where
+        T: Into<Option<bool>>,
+    {
+        self.selective = val.into();
+        self
+    }
+}